Como exibir os caminhos em $ PATH separadamente

29

Eu não consigo descobrir como listar os vários caminhos em $PATH separadamente para que eles fiquem assim:

/bin
/usr/bin
/usr/local/bin

etc.

Alguém sabe a variável correta para isso?

    
por HankG 22.03.2015 / 21:59

14 respostas

39

Experimente sed :

$ sed 's/:/\n/g' <<< "$PATH"

Ou tr :

$ tr ':' '\n' <<< "$PATH"

Ou python :

$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"

Aqui, todos os itens acima substituirão todas as ocorrências de : com novas linhas \n .

    
por heemayl 22.03.2015 / 22:02
54

Use a Expansão de Parâmetros do bash :

echo "${PATH//:/$'\n'}"

Isso substitui todo o : em $PATH por uma nova linha ( \n ) e imprime o resultado. O conteúdo de $PATH permanece inalterado.
Se você quiser substituir apenas o primeiro : , remova a segunda barra: echo -e "${PATH/:/\n}"

    
por Cyrus 22.03.2015 / 22:22
24

Usando o IFS:

(set -f; IFS=:; printf "%s\n" $PATH)

IFS contém os caracteres em que o bash faz a divisão, portanto, um IFS com : faz o bash dividir a expansão de $PATH on : . printf faz um loop nos argumentos sobre a string de formatação até que os argumentos sejam esgotados. Precisamos desabilitar o globbing (expansão de curingas) usando set -f para que os curingas nos nomes dos diretórios PATH não sejam expandidos.

    
por muru 22.03.2015 / 22:07
13

Usando xargs :

xargs -n1 -d: <<< $PATH

Em man xargs

-n max-args
          Use  at  most  max-args  arguments per command line.

 -d delim
          Input  items  are terminated by the specified character.
    
por souravc 23.03.2015 / 14:49
7

Aqui está o equivalente em 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
    
por Nathan Osman 15.10.2016 / 01:50
7

Aqui estão mais algumas abordagens. Estou usando um PATH com diretórios contendo barras invertidas, espaços e até mesmo uma nova linha para mostrar que eles devem funcionar com qualquer coisa (exceto o cut one que falha em novas linhas):

$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even 
new lines
  • Algumas formas Perl:

    $ perl -pe 's/:/\n/g' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    O -p significa "imprimir todas as linhas de entrada depois de aplicar o script fornecido por -e ". O script está usando o operador de substituição ( s/oldnew/ ) para substituir todo : por novas linhas.

    $ perl -lne 'print for split /:/' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    O -l adiciona uma nova linha a cada chamada print . Aqui, o script está dividindo sua entrada em : e, em seguida, faz um loop sobre cada elemento de divisão e o imprime.

    $ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    O -a faz com que perl se comporte como awk : ele dividirá cada uma de suas linhas de entrada no caractere dado por -F (então : , aqui) e salvará o resultado na matriz @F . O $" é uma variável Perl especial, o "separador de lista", cujo valor é impresso entre cada elemento de uma lista impressa. Portanto, configurá-lo para uma nova linha fará com que print @list imprima cada elemento de @list e, em seguida, uma nova linha. Aqui, estamos usando para imprimir @F .

    $ perl -F: -ane 'print join "\n", @F' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    A mesma ideia acima, apenas menos golfe. Em vez de usar $" , explicitamente join ing o array com novas linhas e, em seguida, a impressão.

  • Simples grep com mágica PCRE:

    $ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    O -o faz com que grep imprima apenas a parte correspondente de cada linha, portanto, cada correspondência é impressa em uma linha separada. O -P ativa as PCRE (Perl Compatible Regular Expressions - Expressões Regulares Compatíveis com Perl). A regex está procurando trechos de não : ( [^:]+ ) que seguem o início da linha ( ^ ) ou um caractere : . O \K é um truque PCRE que significa "descartar qualquer coisa que tenha correspondência antes desse ponto" e é usado aqui para evitar a impressão do : também.

  • E uma solução cut (esta falha em novas linhas, mas pode lidar com barras invertidas e espaços):

    $ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    As opções usadas são -d: , que define o delimitador de entrada como : , -f 1- , o que significa imprimir todos os campos (do primeiro ao fim) e --output-delimiter=$'\n' , que define o delimitador de saída. O $'\n' é ANSI C citando e é uma maneira de imprimir uma nova linha personagem no shell.

Em todos os exemplos acima, estou usando o bash (e algumas outras shells ') aqui string ( <<< ) operador para passar uma string como entrada para um programa. Então, command <<<"foo" é equivalente a echo -n "foo" | command . Note que estou sempre citando "$PATH" , sem as aspas, o shell teria comido o caractere de nova linha.

@ 7stud deu outra abordagem em os comentários isso é bom demais para não incluir:

$ perl -0x3a -l012 -pe '' <<<"$PATH"

Isso é conhecido como golfe . O -0 especifica o separador de registro de entrada como um número octal ou hexadecimal. Isso é o que define uma "linha" e seu valor padrão é \n , um caractere de nova linha. Aqui, nós o definimos como : , que é x3a em hexadecimal (tente printf '\x3a\n' ). O -l faz três coisas. Primeiro, ele remove o separador de registro de entrada ( $/ ) do final de cada linha - removendo efetivamente o : aqui - e, em segundo lugar, define o separador de registro de saída ( $\ ) como valor octal ou hexadecimal ( 012 é \n ). Se $\ for definido, ele será adicionado ao final de cada chamada de print , portanto, isso resultará em uma nova linha anexada a cada print .

O -pe irá p rimar cada linha de entrada depois de aplicar o script fornecido por -e . Aqui não há script porque todo o trabalho é feito pelos flags de opções conforme descrito acima!

    
por terdon 15.10.2016 / 12:19
6

Nesta resposta:

  1. C
  2. Python
  3. Ruby
  4. Alternative awk

1. C

Como todas as linguagens de script já foram tiradas, vou com C. É muito fácil obter variáveis de ambiente com a função get_env() (veja GNU C Library documentation ). O resto é simplesmente manipulação de caracteres

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

2. Python

Mas também porque "por que não", aqui está a versão alternativa do python via argumentos de linha de comando sys.argv

python -c 'import sys; print "\n".join([d for d in sys.argv[1].split(":")])' "$PATH"

3. Ruby

O Ruby não vem com o Ubuntu por padrão, ao contrário do compilador C e do interpretador Python, mas se você se vir usando, a solução em Ruby seria:

ruby -ne 'puts $_.split(":")' <<< "$PATH"

Como sugerido por 7stud (Muito obrigado!) no comentários , isso também pode ser encurtado com

ruby -F: -ane 'puts $F' <<<$PATH

e desta forma

ruby -0072 -ne 'puts chomp' <<<$PATH

4. Awk alternativo

Podemos utilizar a função split() para dividir a linha lida em array e usar for-each loop para imprimir cada item em uma linha separada.

awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
    
por Sergiy Kolodyazhnyy 15.10.2016 / 01:40
5

Provavelmente, a única maneira que não foi mencionada é a maneira como venho usando há anos:

echo $PATH | tr ":" "\n"

então, no seu .profile ou .bash_profile ou qualquer outra coisa, você pode adicionar:

alias path='echo $PATH | tr ":" "\n"'

    
por dolt 25.03.2015 / 13:03
3

Através do awk.

echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'

Através do python.

$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
    for i in line.split(":"):
        print(i)'

Observe que o recuo é muito importante em python.

    
por Avinash Raj 23.03.2015 / 13:10
3

Precisamos de mais Java!

public class GetPathByLine {
    public static void main(String[] args) {
        for (String p : System.getenv("PATH").split(":")) {
            System.out.println(p);
        }
    }
}

Salve isso em GetPathByLine.java e compile usando:

javac GetPathByLine.java

Executar com:

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
    
por Kaz Wolfe 15.10.2016 / 02:03
2

Eu uso "Bash Path Functions" de Stephen Collyer (ver artigo dele no Linux Journal ). Isso me permite usar a "lista separada por dois pontos" como um tipo de dados na programação da shell. Por exemplo, posso produzir uma lista de todos os diretórios no diretório atual:

dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done  

Em seguida, listpath -p dirs produz uma lista.

    
por waltinator 22.03.2015 / 23:19
2

Explicação da resposta do @Cyrus

echo "${PATH//:/$'\n'}"

Notas:

ANSI-C Citando - explica $ ' alguns \ ntext '

Expansão do Parâmetro da Shell - explica $ {parameter / pattern / string}, Se o padrão começar com '/', todas as correspondências do padrão serão substituídas por string.

Então nós temos:

  1. um padrão /: que começa com '/' para substituir todas as correspondências
  2. uma string $ '\ n' que é citada com a contração $ 'anytext' para tratar o novo símbolo de linha (\ n).
por victorq10 13.03.2018 / 12:13
1

Outra forma AWK é tratar cada diretório como um registro separado, em vez de um campo separado .

awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"

Acho essa sintaxe particularmente intuitiva. Mas, se quiser, você pode reduzi-lo, tornando o print $0 implícito (é a ação padrão e 1 é avaliado como verdadeiro, fazendo com que seja feito para cada linha):

awk 'BEGIN{RS=":"} 1' <<<"$PATH"

O separador de registro de entrada e saída padrão do AWK é a nova linha (quebra de linha). Ao definir o separador de registro de entrada ( RS ) como : antes de ler a entrada, o AWK analisa automaticamente um $PATH com delimitação de dois pontos em seus nomes de diretório constitutivos. O AWK expande $0 para cada registro inteiro, a nova linha continua a ser o separador de registro saída e não é necessário loop ou 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

O AWK costuma ser usado para analisar registros em campos separados, mas não há necessidade de apenas construir uma lista de nomes de diretório.

Isso funciona até mesmo para entradas contendo espaços em branco (espaços e tabulações), até vários espaços em branco consecutivos:

ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de    fg:h'
ab               c
de    fg
h

Ou seja, a menos que você faça com que o AWK reconstrua o registro (veja abaixo), não há problema em ter espaços ou tabulações (os separadores de campo padrão) na entrada. Seu PATH provavelmente não contém espaços em um sistema Ubuntu, mas se funcionar, isso ainda funcionará.

Vale a pena mencionar, como uma nota lateral, que a capacidade do AWK de interpretar um registro como uma coleção de campos se torna útil para o problema relacionado à construção de uma tabela de diretório componentes :

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

A curiosa atribuição $1=$1 serve para forçar o AWK a reconstruir o registro .

(Isto é provavelmente mais útil para casos em que o processamento adicional deve ser feito nos componentes, do que para o exemplo exato mostrado simplesmente para imprimir a tabela.)

    
por Eliah Kagan 14.01.2017 / 16:09
1
jq -Rr 'gsub(":";"\n")' <<<$PATH
    
por David Fetter 08.04.2018 / 00:00

Tags