Não consigo descobrir como listar os vários caminhos $PATH
separadamente, para que eles fiquem assim:
/bin
/usr/bin
/usr/local/bin
etc.
Alguém sabe a variável correta para isso?
Não consigo descobrir como listar os vários caminhos $PATH
separadamente, para que eles fiquem assim:
/bin
/usr/bin
/usr/local/bin
etc.
Alguém sabe a variável correta para isso?
Respostas:
Tente 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 :
por novas linhas \n
.
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
python -c "print r'$PATH'.replace(':', '\n')"
(usando uma corda em bruto no caso de barras invertidas)
tr
trabalhou para mim (no mac, aliás). Obrigado.
.bash_profile
, adicione-os assim: #alias path='tr ":" "\n" <<< "$PATH"'
Use a expansão de parâmetros do bash :
echo "${PATH//:/$'\n'}"
Tudo isso substitui :
em $PATH
por uma nova linha ( \n
) e imprime o resultado. O conteúdo de $PATH
permanece inalterado.
Se você deseja substituir apenas o primeiro :
, remova a segunda barra:echo -e "${PATH/:/\n}"
${parameter/pattern/string}
Usando IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
mantém os caracteres nos quais o bash se divide, portanto, um IFS
com :
faz com que o bash divida a expansão de $PATH
on :
. printf
faz um loop dos argumentos sobre a string de formato até que os argumentos se esgotem. Precisamos desativar o globbing (expansão de curinga) usando set -f
para que os curingas nos nomes de diretório PATH não sejam expandidos.
Usando xargs
:
xargs -n1 -d: <<< $PATH
De 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 | xargs -n1 -d: echo
redundante ou não importa?
echo $PATH | xargs -n1 -d:
fará o mesmo por você, mas você usará mais um shell. O primeiro avaliará echo $PATH
e canalizará a saída para o próximo shell para fazer o resto.
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
Aqui estão mais algumas abordagens. Estou usando um PATH
com diretórios contendo barras invertidas, espaços e até uma nova linha para mostrar que eles devem funcionar com qualquer coisa (exceto a cut
que falha em novas linhas):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
Algumas maneiras Perl:
$ perl -pe 's/:/\n/g' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
O -p
meio "imprime todas as linhas de entrada após aplicar o script fornecido por -e
". O script está usando o operador de substituição ( s/oldnew/
) para substituir todos :
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 print
chamada. Aqui, o script está dividindo sua entrada :
e, em seguida, faz um loop sobre cada elemento de divisão e a imprime.
$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
As -a
marcas perl
se comportam assim awk
: dividirá cada uma de suas linhas de entrada no caractere fornecido por -F
(então :
, aqui) e salvará o resultado na matriz @F
. A $"
é uma variável especial Perl, o "separador de lista", cujo valor é impressa entre cada elemento de uma lista impressa. Portanto, defini-lo como uma nova linha fará com que print @list
cada elemento seja impresso @list
e, em seguida, uma nova linha. Aqui, estamos usando-o 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 idéia acima, apenas menos golfe. Em vez de usar $"
, estamos explicitamente join
inserindo a matriz com novas linhas e depois imprimindo.
Simples grep
com a magia PCRE:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
O -o
faz grep
imprimir apenas a parte correspondente de cada linha, para que cada correspondência seja impressa em uma linha separada. O -P
permite Perl Compatible Regular Expressions (PCRE). O regex está procurando trechos de não :
( [^:]+
) que seguem o início da linha ( ^
) ou um :
caractere. O \K
é um truque PCRE que significa "nada descarte combinado antes deste ponto" e é usado aqui para evitar a impressão do :
bem.
E uma cut
solução (essa falha nas 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 utilizadas são: -d:
define o delimitador de entrada :
, o -f 1-
que significa imprimir todos os campos (do 1º ao final) e --output-delimiter=$'\n'
define o delimitador de saída. A citação$'\n'
é ANSI C e é uma maneira de imprimir um caractere de nova linha no shell.
Em todos os exemplos acima, estou usando o operador string ( <<<
) de bash (e alguns outros shells) aqui para passar uma string como entrada para um programa. Então command <<<"foo"
é equivalente a echo -n "foo" | command
. Observe que estou sempre citando "$PATH"
, sem as aspas, o shell teria comido o caractere de nova linha.
O @ 7stud deu outra abordagem nos comentários, que é boa 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 que define uma "linha" e seu valor padrão é \n
um caractere de nova linha. Aqui, estamos definindo-o como um :
que está x3a
em hexadecimal (tentativa 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 :
here - e, em segundo lugar, define o separador de registro de saída ( $\
) para qualquer valor octal ou hexadecimal que for dado ( 012
é \n
). Se $\
definido, ele será adicionado ao final de cada print
chamada, resultando em uma nova linha anexada a cada uma print
.
A -pe
vontade p rint cada linha de entrada após a aplicação do roteiro dada por -e
. Aqui não há script, porque todo o trabalho é realizado pelos sinalizadores de opção, conforme descrito acima!
perl -0x3a -l012 -pe '' <<<$PATH
. Explicação: -0
define o separador de registros de entrada (especificado em notação hex / octal, x3A é dois pontos), -l
faz duas coisas: 1) chomps o separador de registros de entrada, 2) define o separador de registros de saída se um for especificado (em notação octal , 012 é uma nova linha). Um -p
loop imprime o valor de $ _, que será lido em cada linha .
-F
informação. Eu uso -F
combinado -an
há anos, nunca percebi que um implicava os outros. A propósito, vi Serg mencionando o Code Golf , mas acho que você também gostaria de Unix e Linux se você gosta desse tipo de coisa.
-l
também adiciona o separador de registros de saída fornecido ao final de cada chamada de impressão. De fato, a impressão sempre adiciona o separador de registros de saída,, $/
ao final de uma string - se o separador de registros de saída estiver definido. Por padrão, é undef. Então, -l
jus define $/
e isso faz com que o print adicione a nova linha no final da string.
Como todas as linguagens de script já foram utilizadas, irei com o C. É muito fácil obter variáveis de ambiente com a get_env()
função (consulte a documentação da GNU C Library ). 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
Mas também porque "por que não", aqui está a versão alternativa do python via argumentos da linha de comando sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
O Ruby não vem com o Ubuntu por padrão, ao contrário do compilador C e do interpretador Python, mas se você o usar, a solução no Ruby seria a seguinte:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Como sugerido pelo 7stud (Muito obrigado!) Nos comentários , isso também pode ser abreviado com
ruby -F: -ane 'puts $F' <<<$PATH
e assim
ruby -0072 -ne 'puts chomp' <<<$PATH
Podemos utilizar a split()
função para dividir a linha lida em matriz e usar o for-each
loop para imprimir cada item em uma linha separada.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
imprime automaticamente os elementos de uma matriz em linhas separadas! Você também pode fazer com que os comutadores façam a divisão: ruby -F: -ane 'puts $F' <<<$PATH
Explicação: -F
define $;
o caractere especificado, que é o separador padrão usado por String :: split ($; tem um valor padrão nil, que se divide em espaço em branco). -a
chama $ _. split, onde $ _ é uma linha lida usando gets ()) e atribui a matriz resultante a $F
.
-F
bandeira - estou apenas começando com Ruby, fazendo as coisas de maneira um pouco grosseira.
ruby -0072 -ne 'puts chomp' <<<$PATH
. Explicação: -0
define o separador de registro de entrada (especifique um caractere no formato octal; 072 é dois pontos). Ruby emprega $ _ de maneira semelhante ao Perl. O método gets () (usado no -n
loop) define $ _ para a linha atual que é lida. E chomp()
sem um argumento, chomps $ _. Eu ainda gosto mais do seu. :)
-F
sinalizador, é mais curto. Se você fizer echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
isso, me informará que são 271 bytes, mas o número octal é 276. Isso é para todo o comando, é claro, se considerarmos que apenas o código em si puts $F
é claramente mais curto. :) A propósito, você conhece o Code Golf ? É o site de soluções para a programação de quebra-cabeças no menor número de bytes. Há uma questão relacionada com esta: codegolf.stackexchange.com/q/96334/55572
Provavelmente, a única maneira que não foi mencionada é a maneira que eu a uso há anos:
echo $PATH | tr ":" "\n"
portanto, em seu .profile ou .bash_profile ou o que for, você pode adicionar:
alias path='echo $PATH | tr ":" "\n"'
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 GetPathByLine.java
e compile usando:
javac GetPathByLine.java
Correr 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
python3 -c "import os; [print(p) for p in os.getenv('PATH').split(':')]"
Através do awk.
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
Através de 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.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
quando você pode simplesmente usar input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
Eu uso "Bash Path Functions" de Stephen Collyer (veja seu artigo no Linux Journal ). Permite-me usar a "lista separada por dois pontos" como um tipo de dados na programação shell. Por exemplo, eu 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
Então, listpath -p dirs
produz uma lista.
Explicação da resposta @Cyrus
echo "${PATH//:/$'\n'}"
Notas:
Citação ANSI-C - explica $ 'some \ ntext'
Expansão de parâmetros do shell - explica $ {parameter / pattern / string}. Se o padrão começa com '/', todas as correspondências do padrão são substituídas por string.
Então nós temos:
Outra maneira do AWK é tratar cada diretório como um registro separado , e não como um campo separado .
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
Acho essa sintaxe particularmente intuitiva. Mas, se quiser, você pode reduzi-lo, tornando print $0
implícito (é a ação padrão e 1
avalia como verdadeira, 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 registros de entrada ( RS
) como :
antes de ler a entrada, o AWK analisa automaticamente dois pontos delimitados por dois pontos $PATH
em seus nomes de diretório constitutivos. O AWK se expande $0
para cada registro inteiro, a nova linha continua sendo o separador de registros de saída e não gsub
é necessário fazer loop ou é necessário.
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 é frequentemente usado para analisar registros em campos separados, mas não há necessidade disso apenas para construir uma lista de nomes de diretórios.
Isso funciona mesmo para entradas que contêm 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 isso acontecer, isso ainda vai funcionar.
Vale ressaltar, como observação lateral, que a capacidade do AWK de interpretar um registro como uma coleção de campos se torna útil para o problema relacionado de construir uma tabela de componentes de diretório :
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 $1=$1
designação curiosa serve para forçar o AWK a reconstruir o registro .
(Isso é provavelmente mais útil nos casos em que um processamento adicional deve ser feito nos componentes, do que no exemplo exato mostrado simplesmente da impressão da tabela.)
jq -Rr 'gsub(":";"\n")' <<<$PATH
Como exibir os caminhos em $ PATH separadamente
Essas são as minhas maneiras preferidas de fazer isso com base nos meus respectivos casos de uso e preocupações sobre compatibilidade e uso de recursos.
tr
Primeiro, se você precisar de uma solução rápida, fácil de lembrar e legível, basta fazer eco PATH
e canalizá-la para translate ( tr
) para transformar os dois pontos em novas linhas:
echo $PATH | tr : "\n"
Ele tem a desvantagem de usar dois processos por causa do canal, mas se estamos apenas invadindo um terminal, realmente nos importamos com isso?
Se você deseja uma solução bastante permanente .bashrc
para uso interativo, pode usar o seguinte comando path
, mas a legibilidade dessa solução é questionável:
alias path="echo \"${PATH//:/$'\n'}\""
Se o padrão começar com '/', todas as correspondências do padrão serão substituídas por uma sequência. Normalmente, apenas a primeira partida é substituída.
O comando acima substitui os dois pontos por novas linhas usando a expansão de parâmetros de shell do Bash :
${parameter/pattern/string}
Para explicar isso:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
Boa sorte lembrando-se disso quando você está apenas invadindo a linha de comando, se ainda não tiver o alias.
Como alternativa, uma abordagem razoavelmente compatível, legível e compreensível que não dependa de nada além do shell é usar a seguinte função (sugiro no seu .bashrc
.)
A função a seguir transforma temporariamente o Separador de Campo Interno (ou Entrada) (IFS) em dois pontos e, quando uma matriz é fornecida printf
, ela é executada até que a matriz seja usada:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
Este método de criação da função , IFS
e printf
são fornecidos pelo POSIX, assim que deve funcionar na maioria POSIX-como conchas (especialmente Dash, que Ubuntu geralmente aliases como sh
).
Você deve usar o Python para isso? Você poderia. Este é o comando Python mais curto que consigo pensar nisso:
python -c "print('\n'.join('${PATH}'.split(':')))"
ou apenas Python 3 (e talvez mais legível?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
Eles devem funcionar em qualquer ambiente shell comum, desde que você possua Python.
Esta solução é mais simples que as soluções Java , C , go e awk :
$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
Aqui está outra grande possibilidade:
$ 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
Isso exigiria a instalação de algumas dependências:
sudo apt-get install openjdk-8-jdk-headless bsh