当前位置: 首页>>技术教程>>正文


bash – 如何将$PATH显示为每行一个目录?

,

问题描述

我无法弄清楚如何分别列出$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就会吃掉换行符。


@7studthe 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将打印每行输入。这里没有脚本,因为所有工作都是由如上所述的选项标志完成的!

第八种答案

  1. C

  2. 红 gems

  3. 替代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

this way

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)'

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/11454.html,未经允许,请勿转载。