问题描述
我无法弄清楚如何分别列出$PATH
中的各种路径,以便它们看起来像这样:
/bin
/usr/bin
/usr/local/bin
如何才能做到这一点?
最佳答案
尝试sed
:
$ sed 's/:/\n/g' <<< "$PATH"
或tr
:
$ tr ':' '\n' <<< "$PATH"
或python
:
$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"
在此,以上所有内容将用新行\n
替换所有出现的:
。
次佳答案
使用bash的Parameter Expansion:
echo "${PATH//:/$'\n'}"
这将用换行符(\n
)替换$PATH
中的所有:
并打印结果。 $PATH
的内容保持不变。如果只想替换第一个:
,请删除第二个斜杠:echo -e "${PATH/:/\n}"
第三种答案
使用IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
保存bash进行拆分的字符,因此带有:
的IFS
使bash在:
上拆分$PATH
的扩展。 printf
在格式字符串上循环参数,直到参数用尽。我们需要使用set -f
禁用通配符(通配符扩展),以便PATH目录名称中的通配符不会被扩展。
第四种答案
使用xargs
:
xargs -n1 -d: <<< $PATH
从man xargs
-n max-args
Use at most max-args arguments per command line.
-d delim
Input items are terminated by the specified character.
第五种答案
可能未提及的唯一方法是我多年来使用它的方法:
echo $PATH | tr ":" "\n"
因此,您可以在.profile或.bash_profile或任何其他内容中添加:
alias path='echo $PATH | tr ":" "\n"'
第六种答案
这是Go中的等效项:
$ cat path.go
package main
import (
"fmt"
"os"
"strings"
)
func main() {
for _, p := range strings.Split(os.Getenv("PATH"), ":") {
fmt.Println(p)
}
}
$ go run path.go
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin
/home/nathan/.local/bin
/home/nathan/go/bin
第七种答案
这里有一些其他方法。我使用的PATH
目录包含反斜杠,空格甚至换行,以表明它们应适用于任何内容(cut
除外,该行在换行符上失败):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
-
一些Perl方式:
$ perl -pe 's/:/\n/g' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
-p
的意思是“应用-e
给出的脚本后打印每条输入行”。该脚本使用替代运算符(s/oldnew/
)将所有:
换行。$ perl -lne 'print for split /:/' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
-l
向每个print
调用添加换行符。在这里,脚本在:
上拆分其输入,然后循环遍历每个拆分元素并进行打印。$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
-a
使得perl
的行为类似于awk
:它将在-F
(此处为:
)给定的字符上分割其每个输入行,并将结果保存在数组@F
中。$"
是一个特殊的Perl变量”list separator”,其值显示在打印列表的每个元素之间。因此,将其设置为换行符将使print @list
打印@list
的每个元素,然后打印换行符。在这里,我们使用它来打印@F
。$ perl -F: -ane 'print join "\n", @F' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
与上述相同的想法,只是打高尔夫球的次数较少。而不是使用
$"
,我们将使用换行符明确地join
对该数组进行换行,然后进行打印。 -
带有PCRE魔术的简单
grep
:$ grep -oP '(^|:)\K[^:]+' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
-o
使得grep
仅打印每行的匹配部分,因此每个匹配项都打印在单独的行上。-P
启用Perl兼容正则表达式(PCRE)。正则表达式正在寻找非:
([^:]+
)的延伸,该延伸是在行首(^
)或:
字符之后。\K
是PCRE的trick俩,意思是“丢弃在此之前匹配的所有内容”,在这里也用于避免打印:
。 -
和
cut
解决方案(该解决方案在换行符上失败,但可以处理反斜杠和空格):$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
使用的选项是
-d:
和--output-delimiter=$'\n'
,-d:
将输入定界符设置为:
,-f 1-
意味着打印所有字段(从第1到末尾),--output-delimiter=$'\n'
则设置输出定界符。$'\n'
是ANSI C引号,是在 shell 中打印换行符的一种方式。
在以上所有示例中,我使用bash的here string(<<<
)运算符将字符串作为输入传递给程序。因此command <<<"foo"
等效于echo -n "foo" | command
。请注意,我总是引用"$PATH"
,不带引号的话,shell就会吃掉换行符。
@7stud在the comments中提供了另一种方法,它太好了,不包含:
$ perl -0x3a -l012 -pe '' <<<"$PATH"
That’s what’s称为golfing。 -0
将输入记录分隔符指定为八进制或十六进制数字。这就是定义”line”的内容,其默认值为\n
(换行符)。在这里,我们将其设置为:
(十六进制为x3a
)(尝试printf '\x3a\n'
)。 -l
做三件事。首先,它从每行的末尾删除输入记录分隔符($/
)—在这里有效地删除了:
;其次,它将输出记录分隔符($\
)设置为给定的八进制或十六进制值(012
为\n
)。如果定义了$\
,则将其添加到每个print
调用的末尾,因此这将导致在每个print
处追加一个换行符。
在应用-e
给出的脚本之后,-pe
将打印每行输入。这里没有脚本,因为所有工作都是由如上所述的选项标志完成的!
第八种答案
-
C
-
红 gems
-
替代awk
1. C
由于已经使用了所有脚本语言,因此我将使用C。使用get_env()
函数获取环境变量非常容易(请参阅GNU C Library documentation)。剩下的只是角色操纵
bash-4.3$ cat get_path.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *path = getenv("PATH");
int length = strlen(path) -1;
for(int i=0;i<=length;i++){
if (path[i] == ':')
path[i] = '\n';
printf("%c",path[i]);
}
printf("\n");
return 0;
}
bash-4.3$ gcc get_path.c
bash-4.3$ ./a.out
/home/xieerqi/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin
/opt/microchip/xc16/v1.25/bin
/opt/microchip/xc32/v1.40/bin
/opt/microchip/xc8/v1.35/bin
/home/xieerqi/bin
/home/xieerqi/bin/sh
也是因为”why not”,这是通过命令行参数sys.argv
的替代python版本
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
3.红 gems
ruby -ne 'puts $_.split(":")' <<< "$PATH"
正如comments中的7stud(非常感谢!)建议的那样,也可以使用
ruby -F: -ane 'puts $F' <<<$PATH
ruby -0072 -ne 'puts chomp' <<<$PATH
4.替代awk
我们可以利用split()
函数将读取的行分解为数组,并使用for-each
循环在单独的行上打印出每个项目。
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
第九种答案
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
将此保存到GetPathByLine.java
,并使用以下命令进行编译:
javac GetPathByLine.java
运行:
java GetPathByLine
┌─[17:06:55]─[kazwolfe@BlackHawk]
└──> ~ $ cat GetPathByLine.java
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
┌─[17:06:58]─[kazwolfe@BlackHawk]
└──> ~ $ javac GetPathByLine.java
┌─[17:07:02]─[kazwolfe@BlackHawk]
└──> ~ $ java GetPathByLine
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin
第十种答案
通过awk。
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
通过python。
$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
for i in line.split(":"):
print(i)'