我无法弄清楚如何分别列出各种路径$PATH
,以便它们看起来像这样:
/bin
/usr/bin
/usr/local/bin
等等
有人知道正确的变量吗?
我无法弄清楚如何分别列出各种路径$PATH
,以便它们看起来像这样:
/bin
/usr/bin
/usr/local/bin
等等
有人知道正确的变量吗?
Answers:
尝试sed
:
$ sed 's/:/\n/g' <<< "$PATH"
或tr
:
$ tr ':' '\n' <<< "$PATH"
或python
:
$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"
在这里,以上所有内容将:
用新行替换所有出现的\n
。
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
python -c "print r'$PATH'.replace(':', '\n')"
tr
为我工作(在Mac,btw上)。谢谢。
.bash_profile
,请像这样添加:alias path='tr ":" "\n" <<< "$PATH"'
使用bash的参数扩展:
echo "${PATH//:/$'\n'}"
这将替换所有:
在$PATH
一个换行符(\n
),并打印出结果。的内容$PATH
保持不变。
如果只想替换第一个:
斜杠,请删除第二个斜杠:echo -e "${PATH/:/\n}"
${parameter/pattern/string}
使用IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
包含bash进行拆分的字符,因此IFS
with :
使bash拆分$PATH
on 的扩展:
。printf
在格式字符串上循环参数,直到参数用尽。我们需要使用禁用通配符(通配符扩展),set -f
以免PATH目录名称中的通配符被扩展。
使用xargs
:
xargs -n1 -d: <<< $PATH
-n max-args
Use at most max-args arguments per command line.
-d delim
Input items are terminated by the specified character.
echo $PATH | xargs -n1 -d: echo
多余还是没关系?
echo $PATH | xargs -n1 -d:
将为您做同样的事情,但是您将再使用一个shell。第一个将进行评估echo $PATH
并将输出通过管道传递到下一个外壳以完成其余工作。
这是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变量中,“列表分隔”,其值被打印的打印列表中的每个元件之间。因此,将其设置为换行符将先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
使用换行符显式地对数组进行排序,然后进行打印。
grep
使用PCRE魔术简单:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
该-o
品牌grep
只打印每条线的匹配部分,所以每个匹配被打印在单独的行。在-P
使Perl兼容的正则表达式(PCRE)。正则表达式正在寻找在行()或字符的开头跟随非:
([^:]+
)的范围。这是PCRE的trick俩,意思是“在此之前丢弃所有匹配的东西”,此处也用于避免打印。 ^
:
\K
:
一个cut
解决方案(该解决方案在换行符上失败,但可以处理反斜杠和空格):
$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
使用的选项是-d:
将输入定界符设置为:
,-f 1-
这意味着打印所有字段(从第一个到最后),--output-delimiter=$'\n'
并设置输出定界符。的$'\n'
是ANSI C报价,并打印在shell换行符的方式。
在以上所有示例中,我在这里使用bash(和其他一些shell)的string(<<<
)运算符将字符串作为输入传递给程序。所以command <<<"foo"
等于echo -n "foo" | command
。请注意,我一直在引用"$PATH"
,如果不使用引号,则shell会吃掉换行符。
$ perl -0x3a -l012 -pe '' <<<"$PATH"
那就是所谓的打高尔夫球。的-0
指定输入记录分隔符为八进制或十六进制数。这就是定义“行”的内容,其默认值为\n
换行符。在这里,我们将其设置:
为x3a
十六进制的a(尝试printf '\x3a\n'
)。该-l
做三件事。首先,它$/
从每行的末尾删除输入记录分隔符()-有效地删除了:
这里的内容;其次,它将输出记录分隔符($\
)设置为给定的任何八进制或十六进制值(012
is \n
)。如果$\
已定义,则将其添加到每个print
调用的末尾,因此这将导致在每一个末尾添加一个换行符print
。
的-pe
意愿p施加由给出的脚本后RINT每个输入行-e
。这里没有脚本,因为所有工作都如上所述由选项标志完成!
perl -0x3a -l012 -pe '' <<<$PATH
。说明:-0
设置输入记录分隔符(以十六进制/八进制表示,x3A是冒号),-l
执行两件事:1)砍掉输入记录分隔符,2)如果指定了一个,则设置输出记录分隔符(以八进制表示) ,012是换行符)。一个-p
循环打印出的$ _值,这将是各行读入。
-F
信息。我已经-F
结合使用-an
多年了,但是我从来没有意识到一个暗示着其他。顺便说一句,我看到Serg提到了Code Golf,但是如果您喜欢这种事情,我想您也会喜欢Unix&Linux。
-l
还将输出记录分隔符添加到每个打印调用的末尾。 实际上,$/
如果定义了输出记录分隔符,print总是将输出记录分隔符,添加到字符串的末尾。默认情况下为undef。因此,-l
jus设置了$/
,这导致print将换行符添加到字符串的末尾。
由于已经使用了所有脚本语言,因此我将使用C。使用get_env()
函数获取环境变量非常容易(请参阅GNU C库文档)。剩下的只是角色操纵
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
但也因为“为什么不这样做”,这是通过命令行参数的替代python版本 sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
与C编译器和Python解释器不同,Ruby默认情况下不随Ubuntu一起提供,但是如果您发现自己正在使用它,则Ruby中的解决方案将是:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
正如7stud(非常感谢!)在评论中所建议的,也可以使用
ruby -F: -ane 'puts $F' <<<$PATH
而这种方式
ruby -0072 -ne 'puts chomp' <<<$PATH
我们可以利用split()
函数将读取的行分解为数组,并使用for-each
循环在单独的行上打印出每个项目。
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
自动在单独的行上打印数组的元素!您还可以使开关进行拆分:ruby -F: -ane 'puts $F' <<<$PATH
说明:-F
设置$;
为指定的字符,这是String :: split使用的默认分隔符($;默认值为nil,在空白处拆分)。 -a
调用$ _。split,其中$ _是使用gets()读取的行,并将结果数组分配给$F
。
-F
标志-我只是从Ruby开始,所以做的事情有些粗略。
ruby -0072 -ne 'puts chomp' <<<$PATH
。说明:-0
设置输入记录分隔符(指定八进制格式的字符; 072为冒号)。Ruby以类似于Perl的方式使用$ _。gets()方法(在-n
循环中使用)将$ _设置为读入的当前行。并且chomp()
没有arg的情况下,chomps $ _。我还是喜欢你的 :)
-F
标志的那个较短。如果执行echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
此操作,将告诉我它是271个字节,但是八进制数是276个字节。当然,这适用于整个命令,如果我们认为仅代码本身 puts $F
明显较短。:)顺便问一下,您了解Code Golf吗?该站点提供了最短字节数编程难题的解决方案。有一个与此相关的问题:codegolf.stackexchange.com/q/96334/55572
我们需要更多的Java!
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
python3 -c "import os; [print(p) for p in os.getenv('PATH').split(':')]"
通过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)'
请注意,缩进在python中非常重要。
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
只在使用时才会打扰input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
我使用Stephen Collyer的“ Bash Path Functions”(请参阅Linux Journal中他的文章)。它允许我在外壳程序编程中使用“冒号分隔的列表”作为数据类型。例如,我可以通过以下方式生成当前目录中所有目录的列表:
dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done
然后,listpath -p dirs
产生一个列表。
另一种AWK方法是将每个目录视为单独的记录,而不是单独的字段。
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
我发现该语法特别直观。但是,如果您愿意,可以通过print $0
隐式来缩短它(这是默认操作,1
其结果为true,导致每行都要完成):
awk 'BEGIN{RS=":"} 1' <<<"$PATH"
AWK的默认输入和输出记录分隔符是换行符(换行符)。通过在读取输入之前将输入记录分隔符(RS
)设置为:
,AWK会自动将一个冒号分隔的内容解析$PATH
为其组成的目录名称。AWK扩展$0
到每个完整的记录,换行符保留为输出记录分隔符,并且不需要循环或gsub
不需要。
ek@Io:~$ echo "$PATH"
/home/ek/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
/home/ek/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin
AWK通常用于将记录解析为单独的字段,但是并不需要仅构造目录名称列表。
即使对于包含空格(空格和制表符)的输入,甚至多个连续的空格,这也适用:
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de fg:h'
ab c
de fg
h
也就是说,除非您使AWK 重建记录(请参见下文),否则在输入中包含空格或制表符(默认字段分隔符)没有问题。您PATH
的Ubuntu系统上可能不包含空格,但是如果包含空格,则仍然可以使用。
值得一提的,作为一个方面说明,这AWK的解释记录作为字段的集合能力成为构建目录表的相关问题有用的成分:
ek@Io:~$ awk -F/ 'BEGIN{RS=":"; OFS="\t"} {$1=$1; print $0}' <<<"$PATH"
home ek bin
usr local sbin
usr local bin
usr sbin
usr bin
sbin
bin
usr games
usr local games
snap bin
奇怪的$1=$1
任务是为了迫使AWK 重建记录。
(对于要对组件进行其他处理的情况,这可能比仅打印表格的确切示例更有用。)
如何分别显示$ PATH中的路径
这些是我根据各自的用例以及对兼容性和资源使用的关注而首选的方式。
tr
首先,如果您需要一种快速,易记且易读的解决方案,只需回显PATH
并将其通过管道传递给translation(tr
),即可将冒号变成换行符:
echo $PATH | tr : "\n"
由于管道的原因,它具有使用两个进程的缺点,但是如果我们只是在终端中进行黑客入侵,我们真的在乎吗?
如果您想要一个永久性的解决方案.bashrc
供交互使用,则可以将以下命令别名为path
,但是该解决方案的可读性值得怀疑:
alias path="echo \"${PATH//:/$'\n'}\""
如果pattern以'/'开头,则pattern的所有匹配项都将替换为字符串。通常只替换第一场比赛。
上面的命令使用Bash的Shell参数扩展将冒号替换为换行符:
${parameter/pattern/string}
解释一下:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
不过,如果您没有对别名进行别名,那么当您只是在命令行中进行黑客攻击时,请记住这一点。
另外,一种完全交叉兼容,可读和可理解的方法,除了外壳程序外不依赖任何其他方法,可以使用以下功能(我建议在您的中.bashrc
。)
以下函数暂时使内部(或输入)字段分隔符(IFS)成为冒号,并且当给数组时printf
,它将执行直到数组用完为止:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
posix提供了这种函数创建,IFS
和方法printf
,因此它应该可以在大多数类似posix的shell中使用(尤其是Dash,Ubuntu通常将其别名为sh
)。
您应该为此使用Python吗?你可以。这是我可以想到的最短的Python命令:
python -c "print('\n'.join('${PATH}'.split(':')))"
或仅适用于Python 3(也许更具可读性?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
只要您拥有Python,它们也可以在任何通常的shell环境中工作。
该解决方案比Java,C,go和awk解决方案简单:
$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
这是另一种可能性:
$ jrunscript -classpath /usr/share/java/bsh.jar -e 'print(java.lang.System.getenv("PATH").replaceAll(":","\n"))'
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
这将需要安装一些依赖项:
sudo apt-get install openjdk-8-jdk-headless bsh