Non riesco a capire come elencare i vari percorsi $PATH
separatamente in modo che appaiano così:
/bin
/usr/bin
/usr/local/bin
eccetera.
Qualcuno conosce la variabile corretta per questo?
Non riesco a capire come elencare i vari percorsi $PATH
separatamente in modo che appaiano così:
/bin
/usr/bin
/usr/local/bin
eccetera.
Qualcuno conosce la variabile corretta per questo?
Risposte:
Prova sed
:
$ sed 's/:/\n/g' <<< "$PATH"
Oppure tr
:
$ tr ':' '\n' <<< "$PATH"
Oppure python
:
$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"
Qui tutto quanto sopra sostituirà tutte le occorrenze di :
con nuove righe \n
.
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
python -c "print r'$PATH'.replace(':', '\n')"
(usando una stringa grezza in caso di barre rovesciate)
tr
ha funzionato per me (su Mac, BTW). Grazie.
.bash_profile
, aggiungilo così:alias path='tr ":" "\n" <<< "$PATH"'
Usa l' espansione dei parametri di bash :
echo "${PATH//:/$'\n'}"
Questo sostituisce all :
in $PATH
con una newline ( \n
) e stampa il risultato. Il contenuto di $PATH
rimane invariato.
Se desideri sostituire solo il primo :
, rimuovi la seconda barra:echo -e "${PATH/:/\n}"
${parameter/pattern/string}
Utilizzando IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
contiene i personaggi su cui bash si divide, quindi un IFS
con :
fa bash dividere l'espansione di $PATH
on :
. printf
esegue il loop degli argomenti sulla stringa di formato fino a quando gli argomenti sono esauriti. Dobbiamo disabilitare il globbing (espansione con caratteri jolly) in set -f
modo che i caratteri jolly nei nomi delle directory PATH non vengano espansi.
Utilizzando xargs
:
xargs -n1 -d: <<< $PATH
A partire dal 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
essere ridondante o non importa?
echo $PATH | xargs -n1 -d:
farà la stessa cosa per te ma userai un'altra shell. Il primo valuterà echo $PATH
e invierà l' output alla shell successiva per fare il resto.
Ecco l'equivalente in 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
Ecco alcuni altri approcci. Sto usando un PATH
con le directory che contengono barre rovesciate, spazi e persino una nuova riga per mostrare che dovrebbero funzionare con qualsiasi cosa (tranne cut
quella che fallisce nelle newline):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
Alcuni modi Perl:
$ perl -pe 's/:/\n/g' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Il -p
mezzo "stampa ogni riga di input dopo aver applicato lo script fornito da -e
". Lo script utilizza l'operatore di sostituzione ( s/oldnew/
) per sostituire tutto :
con le nuove righe.
$ perl -lne 'print for split /:/' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Il -l
aggiunge un ritorno a capo ad ogni print
chiamata. Qui, lo script sta dividendo il suo input :
e quindi scorre su ogni elemento split e lo stampa.
$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
I -a
make si perl
comportano come awk
: dividerà ciascuna delle sue righe di input sul carattere dato da -F
(quindi :
, qui) e salverà il risultato nella matrice @F
. La $"
è una variabile speciale Perl, la "lista separatore", il cui valore viene stampato tra ogni elemento di una lista stampata. Quindi impostandolo su una nuova riga, verrà print @list
stampato ogni elemento @list
e quindi una nuova riga. Qui, lo stiamo usando per stampare @F
.
$ perl -F: -ane 'print join "\n", @F' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Stessa idea come sopra, solo meno giocata a golf. Invece di usare $"
, stiamo esplicitamente join
eseguendo l'array con nuove righe e quindi stampando.
Semplice grep
con la magia PCRE:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
I -o
marchi grep
stampare solo la porzione corrispondente di ciascuna linea, quindi ogni partita viene stampata su una linea separata. Il -P
permette Perl espressioni regolari compatibili (PCRE). Il regex è alla ricerca di tratti di non :
( [^:]+
) che seguono l'inizio della riga ( ^
) o un :
carattere. Si \K
tratta di un trucco PCRE che significa "scarta qualsiasi cosa abbinata prima di questo punto" e viene usato qui per evitare di stampare :
anche.
E una cut
soluzione (questa fallisce su newline, ma può occuparsi di barre rovesciate e spazi):
$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Le opzioni utilizzate sono quelle -d:
che impostano il delimitatore di input su :
, il -f 1-
che significa stampare tutti i campi (dal 1 ° alla fine) e --output-delimiter=$'\n'
che imposta il delimitatore di output. Il $'\n'
è ANSI C citare ed è un modo per stampare un carattere di nuova riga nel guscio.
In tutti gli esempi precedenti, sto usando l' operatore string ( <<<
) qui di bash (e alcune altre shell ) per passare una stringa come input per un programma. Quindi command <<<"foo"
è equivalente a echo -n "foo" | command
. Nota che sto sempre citando "$PATH"
, senza le virgolette, la shell avrebbe mangiato il carattere di nuova riga.
@ 7stud ha dato un altro approccio nei commenti che è semplicemente troppo bello per non includere:
$ perl -0x3a -l012 -pe '' <<<"$PATH"
Questo è ciò che è noto come il golf . La -0
specifica il separatore di record di ingresso come un numero ottale o esadecimale. Questo è ciò che definisce una "linea" e il suo valore predefinito è \n
un carattere di nuova riga. Qui, lo stiamo impostando su un :
che è x3a
in esadecimale (provare printf '\x3a\n'
). La -l
fa tre cose. Innanzitutto rimuove il separatore del record di input ( $/
) dalla fine di ogni riga — rimuovendo effettivamente il :
qui — e, in secondo luogo, imposta il separatore del record di output ( $\
) su qualunque valore ottale o esadecimale che viene dato ( 012
è \n
). Se $\
definito, viene aggiunto alla fine di ogni print
chiamata, quindi ciò comporterà una nuova riga aggiunta a ciascuna print
.
La -pe
volontà p Rint ciascuna linea di ingresso dopo l'applicazione dello script in -e
. Qui non esiste uno script perché tutto il lavoro viene svolto dai flag delle opzioni come descritto sopra!
perl -0x3a -l012 -pe '' <<<$PATH
. Spiegazione: -0
imposta il separatore del record di input (specificato nella notazione esadecimale / ottale, x3A è un punto e virgola), -l
fa due cose: 1) crea il separatore del record di input, 2) imposta il separatore del record di output se specificato (in notazione ottale , 012 è una nuova riga). Un -p
ciclo stampa il valore di $ _, che verrà letto in ogni riga .
-F
informazioni. Ho usato -F
insieme -an
per anni, non ho mai capito che l'uno implicava gli altri. A proposito, ho visto Serg menzionato Code Golf , ma penso che ti piacerà anche Unix e Linux se ti piacciono queste cose.
-l
aggiunge anche il separatore del record di output fornito alla fine di ogni chiamata di stampa. In effetti, print aggiunge sempre il separatore del record di output $/
, alla fine di una stringa, se viene definito il separatore del record di output. Di default è indefinito. Quindi -l
jus imposta $/
e ciò fa sì che print aggiunga la nuova riga alla fine della stringa.
Probabilmente l'unico modo che non è stato menzionato è il modo in cui lo uso da anni:
echo $PATH | tr ":" "\n"
quindi, nel tuo .profile o .bash_profile o altro, puoi aggiungere:
alias path='echo $PATH | tr ":" "\n"'
Dato che tutti i linguaggi di scripting sono già stati adottati, andrò con C. È abbastanza facile ottenere variabili di ambiente con get_env()
funzione (vedere la documentazione della libreria GNU C ). Il resto è semplicemente manipolazione del personaggio
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
Ma anche perché "why not", ecco la versione alternativa di Python tramite argomenti da riga di comando sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
Ruby non viene fornito con Ubuntu per impostazione predefinita, a differenza del compilatore C e dell'interprete Python, ma se mai ti ritrovi a usarlo, la soluzione in Ruby sarebbe questa:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Come suggerito da 7stud (Grazie mille!) Nei commenti , anche questo può essere abbreviato
ruby -F: -ane 'puts $F' <<<$PATH
e in questo modo
ruby -0072 -ne 'puts chomp' <<<$PATH
Siamo in grado di utilizzare la split()
funzione per suddividere la riga letta in matrice e utilizzare il for-each
ciclo per stampare ogni elemento su una riga separata.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
stampa automaticamente gli elementi di un array su linee separate! Puoi anche fare in modo che gli switch eseguano la divisione: ruby -F: -ane 'puts $F' <<<$PATH
Spiegazione: -F
imposta $;
sul carattere specificato, che è il separatore predefinito usato da String :: split ($; ha un valore predefinito nullo, che si divide su spazi bianchi). -a
chiama $ _. split, dove $ _ è una riga letta usando get ()) e assegna l'array risultante a $F
.
-F
bandiera - ho appena iniziato con Ruby, quindi sto facendo le cose in modo leggermente rozzo.
ruby -0072 -ne 'puts chomp' <<<$PATH
. Spiegazione: -0
imposta il separatore del record di input (specificare un carattere in formato ottale; 072 è due punti). Ruby impiega $ _ in modo simile a Perl. Il metodo gets () (usato nel -n
ciclo) imposta $ _ sulla riga corrente che viene letta. E chomp()
senza arg, chomps $ _. Mi piace ancora di più il tuo. :)
-F
bandiera, è più breve. Se lo fai echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
mi dice che è 271, byte, ma quello con il numero ottale è 276. Questo è per l'intero comando, ovviamente, Se consideriamo che solo il codice stesso puts $F
è chiaramente più corto. :) A proposito, conosci Code Golf ? È il sito per soluzioni per la programmazione di puzzle nel minor numero di byte. C'è una domanda relativa a questa: codegolf.stackexchange.com/q/96334/55572
Abbiamo bisogno di più Java!
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
Salvalo in GetPathByLine.java
e compila usando:
javac GetPathByLine.java
Corri con:
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(':')]"
Attraverso awk.
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
Attraverso il pitone.
$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
for i in line.split(":"):
print(i)'
Nota che il rientro è molto importante in Python.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
quando potresti semplicemente usare input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
Uso "Bash Path Functions" di Stephen Collyer (vedi il suo articolo nel Linux Journal ). Mi permette di usare la "lista separata da due punti" come tipo di dati nella programmazione della shell. Ad esempio, posso produrre un elenco di tutte le directory nella directory corrente:
dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done
Quindi, listpath -p dirs
produce un elenco.
Spiegazione per la risposta di @Cyrus
echo "${PATH//:/$'\n'}"
Gli appunti:
Citazioni ANSI-C - spiega $ 'some \ ntext'
Espansione dei parametri della shell : spiega $ {parametro / modello / stringa}, se il modello inizia con '/', tutte le corrispondenze del modello vengono sostituite con stringa.
Quindi abbiamo:
Un altro modo AWK è quello di trattare ogni directory come un record separato , piuttosto che come un campo separato .
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
Trovo che la sintassi sia particolarmente intuitiva. Ma, se lo desideri, puoi accorciarlo rendendo print $0
implicito (è l'azione predefinita e 1
restituisce true, facendolo eseguire per ogni riga):
awk 'BEGIN{RS=":"} 1' <<<"$PATH"
Il separatore di record di input e output predefinito di AWK è la nuova riga (interruzione di riga). Impostando il separatore del record di input ( RS
) su :
prima di leggere l'input, AWK analizza automaticamente un delimitato dai due punti $PATH
nei suoi nomi di directory costitutivi. AWK si espande $0
per ogni intero record, la nuova riga rimane il separatore del record di output e non gsub
è necessario il looping .
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 viene spesso utilizzato per analizzare i record in campi separati, ma non è necessario solo per costruire un elenco di nomi di directory.
Funziona anche con input contenenti spazi (spazi e tabulazioni), anche più spazi consecutivi:
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de fg:h'
ab c
de fg
h
Cioè, a meno che tu non induca AWK a ricostruire il record (vedi sotto), non è un problema avere spazi o tabulazioni (i separatori di campo predefiniti) nell'input. PATH
Probabilmente il tuo non contiene spazi su un sistema Ubuntu, ma se lo fa, funzionerà comunque.
Vale la pena ricordare, come nota a margine, che la capacità di AWK di interpretare un record come una raccolta di campi diventa utile per il relativo problema di costruzione di una tabella di componenti di directory :
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
Il curioso $1=$1
incarico ha lo scopo di costringere AWK a ricostruire il record .
(Ciò è probabilmente più utile nei casi in cui è necessario eseguire ulteriori elaborazioni sui componenti, rispetto all'esempio esatto mostrato semplicemente di stampare la tabella.)
jq -Rr 'gsub(":";"\n")' <<<$PATH
Come visualizzare i percorsi in $ PATH separatamente
Questi sono i miei modi preferiti per farlo in base ai miei rispettivi casi d'uso e alle preoccupazioni sulla compatibilità e sull'utilizzo delle risorse.
tr
In primo luogo, se hai bisogno di una soluzione rapida, facile da ricordare e leggibile, fai semplicemente eco PATH
e convoglilo per translate ( tr
) per trasformare i due punti in nuove righe:
echo $PATH | tr : "\n"
Ha il rovescio della medaglia di usare due processi a causa della pipe, ma se stiamo solo hackerando in un terminale, ci interessa davvero?
Se si desidera una soluzione abbastanza permanente in .bashrc
uso interattivo, è possibile alias il seguente comando path
, ma la leggibilità di questa soluzione è discutibile:
alias path="echo \"${PATH//:/$'\n'}\""
Se il motivo inizia con '/', tutte le corrispondenze del motivo vengono sostituite con una stringa. Normalmente viene sostituita solo la prima partita.
Il comando sopra sostituisce i due punti con le nuove righe usando l' espansione dei parametri della shell di Bash :
${parameter/pattern/string}
Per spiegarlo:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
Buona fortuna a ricordarlo quando stai solo hackerando dalla riga di comando, se non lo hai ancora fatto.
In alternativa, un approccio abbastanza cross-compatibile, leggibile e comprensibile che non si basa su qualcosa di diverso dalla shell è l'uso della seguente funzione (suggerisco nel tuo .bashrc
.)
La seguente funzione rende temporaneamente il separatore di campo interno (o input) (IFS) due punti e, quando viene assegnato un array printf
, viene eseguito fino a quando l'array non viene esaurito:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
Questo metodo di creazione funzione , IFS
e printf
sono fornite da POSIX, così dovrebbe funzionare nella maggior POSIX come gusci (specialmente Dash, che Ubuntu solitamente alias quanti sh
).
Dovresti usare Python per questo? Potresti. Questo è il comando Python più breve che mi viene in mente per questo:
python -c "print('\n'.join('${PATH}'.split(':')))"
o solo Python 3 (e forse più leggibile?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
Dovrebbero funzionare anche in qualsiasi normale ambiente shell, purché tu abbia Python.
Questa soluzione è più semplice delle soluzioni 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
Ecco un'altra grande possibilità:
$ 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
Ciò richiederebbe l'installazione di alcune dipendenze:
sudo apt-get install openjdk-8-jdk-headless bsh