Ich kann nicht herausfinden, wie die verschiedenen Pfade in $PATH
getrennt aufgeführt werden, so dass sie wie folgt aussehen:
/bin
/usr/bin
/usr/local/bin
usw.
Kennt jemand die richtige Variable dafür?
Ich kann nicht herausfinden, wie die verschiedenen Pfade in $PATH
getrennt aufgeführt werden, so dass sie wie folgt aussehen:
/bin
/usr/bin
/usr/local/bin
usw.
Kennt jemand die richtige Variable dafür?
Antworten:
Versuchen Sie sed
:
$ sed 's/:/\n/g' <<< "$PATH"
Oder tr
:
$ tr ':' '\n' <<< "$PATH"
Oder python
:
$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"
Hier werden alle oben genannten Punkte :
durch neue Zeilen ersetzt \n
.
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
python -c "print r'$PATH'.replace(':', '\n')"
(mit einem rohen String im Falle von Backslashes)
tr
arbeitete für mich (auf dem Mac, übrigens). Vielen Dank.
.bash_profile
es wie folgt:alias path='tr ":" "\n" <<< "$PATH"'
Verwenden Sie die Parametererweiterung von bash :
echo "${PATH//:/$'\n'}"
Dies ersetzt all :
in $PATH
durch eine neue Zeile ( \n
) und gibt das Ergebnis aus. Der Inhalt von $PATH
bleibt unverändert.
Wenn Sie nur den ersten ersetzen möchten :
, entfernen Sie den zweiten Schrägstrich:echo -e "${PATH/:/\n}"
${parameter/pattern/string}
Verwendung von IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
Enthält die Zeichen, für die die Bash-Aufteilung ausgeführt wird. IFS
Mit :
der Option with wird die Aufteilung der Erweiterung von $PATH
on ausgeführt :
. printf
Schleifen Sie die Argumente über die Formatzeichenfolge, bis die Argumente erschöpft sind. Wir müssen das Globbing (Platzhaltererweiterung) mit deaktivieren, set -f
damit Platzhalter in PATH-Verzeichnisnamen nicht erweitert werden.
Verwenden von xargs
:
xargs -n1 -d: <<< $PATH
Von 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
redundant sein oder ist das egal?
echo $PATH | xargs -n1 -d:
wird das gleiche für Sie tun, aber Sie werden eine weitere Shell verwenden. Der erste Befehl wertet die echo $PATH
Ausgabe aus und leitet sie an die nächste Shell weiter, um den Rest zu erledigen.
Hier ist das Äquivalent 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
Hier sind einige weitere Ansätze. Ich benutze ein PATH
mit Verzeichnissen, die Backslashes, Leerzeichen und sogar eine neue Zeile enthalten, um zu zeigen, dass sie mit irgendetwas funktionieren sollten (außer dem cut
, das in Newlines fehlschlägt):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
Einige Perl-Möglichkeiten:
$ perl -pe 's/:/\n/g' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Das -p
bedeutet "drucke jede Eingabezeile nach Anwendung des von gegebenen Skripts -e
". Das Skript verwendet den Substitutionsoperator ( s/oldnew/
), um alle :
Zeilen durch Zeilenumbrüche zu ersetzen .
$ perl -lne 'print for split /:/' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Das -l
fügt jedem print
Anruf eine neue Leitung hinzu . Hier :
teilt das Skript seine Eingabe auf und durchläuft dann jedes geteilte Element und druckt es aus.
$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Die -a
Marken perl
verhalten sich wie awk
: Sie teilen jede ihrer Eingabezeilen auf das von -F
(also :
hier) angegebene Zeichen und speichern das Ergebnis im Array @F
. Das $"
ist eine spezielle Perl-Variable, das "Listentrennzeichen", dessen Wert zwischen jedem Element einer gedruckten Liste gedruckt wird. Wenn Sie also eine neue Zeile festlegen, wird print @list
jedes Element von @list
und dann eine neue Zeile gedruckt. Hier verwenden wir es zum Drucken @F
.
$ perl -F: -ane 'print join "\n", @F' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Gleiche Idee wie oben, nur weniger Golf. Anstatt zu verwenden $"
, wird join
das Array explizit mit Zeilenumbrüchen versehen und dann gedruckt.
Einfach grep
mit PCRE magic:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Die -o
Marken grep
gedruckt werden nur den passenden Abschnitt jeder Linie, so dass jedes Spiel in einer separaten Zeile gedruckt wird. Das -P
aktiviert Perl-kompatible reguläre Ausdrücke (PCRE). Der Regex sucht nach Abschnitten von non- :
( [^:]+
), die entweder auf den Anfang der Zeile ( ^
) oder auf ein :
Zeichen folgen . Das \K
ist ein Trick PCRE das bedeutet „Discard etwas vor diesem Punkt angepasst“ und wird hier zu vermeiden , die den Druck :
als auch.
Und eine cut
Lösung (diese schlägt in Zeilenumbrüchen fehl, kann aber mit Backslashes und Leerzeichen umgehen):
$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Es werden folgende Optionen verwendet: -d:
Setzt den Eingabebegrenzer auf :
, -f 1-
dh druckt alle Felder (vom 1. bis zum Ende) und --output-delimiter=$'\n'
setzt den Ausgabebegrenzer. Das $'\n'
ist ANSI C-Anführungszeichen und ist eine Möglichkeit, ein Zeilenumbruchzeichen in der Shell zu drucken.
In allen obigen Beispielen verwende ich den Operator string ( <<<
) von bash (und einigen anderen Shells ), um einen String als Eingabe für ein Programm zu übergeben. Ist command <<<"foo"
also gleichbedeutend mit echo -n "foo" | command
. Beachten Sie, dass ich immer zitiere "$PATH"
, ohne die Anführungszeichen hätte die Shell das Zeilenumbruchszeichen gegessen.
@ 7stud gab einen anderen Ansatz in den Kommentaren an , der einfach zu gut ist, um ihn nicht einzuschließen :
$ perl -0x3a -l012 -pe '' <<<"$PATH"
Das nennt man Golfen . Das -0
gibt das Eingabesatztrennzeichen als Oktal- oder Hexadezimalzahl an. Dies definiert eine "Linie" und ihr Standardwert ist \n
ein Zeilenumbruchzeichen. Hier sind wir es auf eine Einstellung , :
die ist x3a
in hex (Versuch printf '\x3a\n'
). Das -l
macht drei Dinge. Zunächst das Eingangsdatensatztrennzeichen (entfernt $/
) von dem Ende jeder Zeile effektiv Entfernen des :
Hier und zweiten, den Ausgabesatz Separator (Sets $\
), was auch immer Oktal oder Hexadezimalwert ihm gegeben wird ( 012
ist \n
). Wenn dies $\
definiert ist, wird es am Ende jedes print
Anrufs hinzugefügt , sodass an jeden eine neue Zeile angehängt wird print
.
Der -pe
Wille p rint jede Eingabezeile nach dem Skript von bestimmten Anwendung -e
. Hier gibt es kein Skript, da die gesamte Arbeit mit den oben beschriebenen Options-Flags erledigt wird!
perl -0x3a -l012 -pe '' <<<$PATH
. Erläuterung: Legt das Trennzeichen für Eingabedatensätze fest (in -0
hexadezimaler / oktaler Schreibweise angegeben, x3A ist ein Doppelpunkt), -l
führt zwei Aktionen aus: 1) Legt das Trennzeichen für Eingabedatensätze fest, 2) Legt das Trennzeichen für Ausgabedatensätze fest, wenn eines angegeben ist (in oktaler Schreibweise) , 012 ist ein Zeilenumbruch). Eine -p
Schleife gibt den Wert von $ _ aus, der in jeder Zeile eingelesen wird.
-F
Info. Ich benutze seit Jahren das -F
Kombinierte mit -an
. Ich habe nie bemerkt, dass das eine das andere impliziert. Übrigens, ich habe gesehen, dass Serg Code Golf erwähnt hat , aber ich denke, dass Sie auch Unix und Linux mögen, wenn Sie sich für solche Dinge interessieren.
-l
auch das Trennzeichen für Ausgabesätze hinzu, das am Ende jedes Druckaufrufs angegeben wird. Tatsächlich fügt print das Trennzeichen für Ausgabedatensätze immer $/
am Ende einer Zeichenfolge ein - wenn das Trennzeichen für Ausgabedatensätze definiert ist. Standardmäßig ist es undef. Also -l
setzt jus $/
und das bewirkt, dass print die neue Zeile an das Ende der Zeichenkette anfügt.
Da alle Skriptsprachen bereits verwendet wurden, gehe ich zu C. Es ist ziemlich einfach, Umgebungsvariablen mit get_env()
function zu erhalten (siehe GNU C Library-Dokumentation ). Der Rest ist einfach Zeichenmanipulation
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
Aber auch, weil "warum nicht", hier eine alternative Python-Version über Kommandozeilenargumente sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
Ruby wird nicht standardmäßig mit Ubuntu geliefert, im Gegensatz zu C-Compiler und Python-Interpreter. Wenn Sie es jedoch jemals verwenden, lautet die Lösung in Ruby wie folgt:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Wie von 7stud (Vielen Dank!) In den Kommentaren vorgeschlagen , kann dies auch mit gekürzt werden
ruby -F: -ane 'puts $F' <<<$PATH
und so
ruby -0072 -ne 'puts chomp' <<<$PATH
Wir können die split()
Funktion verwenden, um die gelesene Zeile in ein Array aufzuteilen, und die for-each
Schleife verwenden, um jedes Element in einer separaten Zeile auszudrucken.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
druckt die Elemente eines Arrays automatisch in separate Zeilen! Sie können auch festlegen, dass die Schalter die Aufteilung durchführen: ruby -F: -ane 'puts $F' <<<$PATH
Erläuterung: -F
Wird $;
auf das angegebene Zeichen festgelegt. Dies ist das von String :: split verwendete Standardtrennzeichen ($; hat den Standardwert nil, der auf Leerzeichen aufgeteilt wird). -a
ruft $ _. split auf, wobei $ _ eine mit gets ()) eingelesene Zeile ist und das resultierende Array zuweist $F
.
-F
Flagge gibt - ich fange gerade mit Ruby an und mache die Dinge ein bisschen grob.
ruby -0072 -ne 'puts chomp' <<<$PATH
. Erläuterung: -0
Legt das Trennzeichen für Eingabesätze fest (geben Sie ein Zeichen im Oktalformat an; 072 ist ein Doppelpunkt). Ruby verwendet $ _ auf ähnliche Weise wie Perl. Die gets () -Methode (in der -n
Schleife verwendet) setzt $ _ auf die aktuelle Zeile , die eingelesen wird. Und chomp()
ohne ein Argument, chomps $ _. Ich mag deine immer noch besser. :)
-F
flag gepostet haben, kürzer. Wenn Sie das tun echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
, heißt das, dass es 271 Bytes sind, aber die mit der Oktalzahl ist 276. Das gilt natürlich für den gesamten Befehl. Wenn wir nur den Code selbst betrachten, puts $F
ist dieser deutlich kürzer. :) Übrigens, kennen Sie Code Golf ? Es ist die Seite für Lösungen zum Programmieren von Rätseln in kürzester Anzahl von Bytes. Es gibt eine Frage zu dieser: codegolf.stackexchange.com/q/96334/55572
Wahrscheinlich ist der einzige Weg, der nicht erwähnt wurde, der Weg, den ich seit Jahren benutze:
echo $PATH | tr ":" "\n"
In Ihrem .profile oder .bash_profile oder was auch immer können Sie Folgendes hinzufügen:
alias path='echo $PATH | tr ":" "\n"'
Wir brauchen mehr Java!
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
Speichern Sie dies in GetPathByLine.java
und kompilieren Sie es mit:
javac GetPathByLine.java
Laufen mit:
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(':')]"
Durch awk.
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
Durch Python.
$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
for i in line.split(":"):
print(i)'
Beachten Sie, dass Einrückungen in Python sehr wichtig sind.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
wenn Sie nur verwenden könnten input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
Ich benutze Stephen Collyers "Bash Path Functions" (siehe seinen Artikel im Linux Journal ). Es erlaubt mir, die "durch Doppelpunkte getrennte Liste" als Datentyp in der Shell-Programmierung zu verwenden. Zum Beispiel kann ich eine Liste aller Verzeichnisse im aktuellen Verzeichnis erstellen, indem ich:
dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done
Dann listpath -p dirs
wird eine Liste erstellt.
Erklärung zur @ Cyrus-Antwort
echo "${PATH//:/$'\n'}"
Anmerkungen:
ANSI-C Quoting - erklärt $ 'some \ ntext'
Shell Parameter Expansion - erklärt $ {parameter / pattern / string}. Wenn pattern mit '/' beginnt, werden alle Übereinstimmungen von pattern durch string ersetzt.
Also haben wir:
Eine andere AWK-Methode besteht darin, jedes Verzeichnis als separaten Datensatz und nicht als separates Feld zu behandeln .
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
Ich finde diese Syntax besonders intuitiv. Wenn Sie möchten, können Sie es jedoch verkürzen, indem Sie das print $0
implizite Element festlegen (dies ist die Standardaktion, 1
die mit true ausgewertet wird und für jede Zeile ausgeführt wird):
awk 'BEGIN{RS=":"} 1' <<<"$PATH"
Das standardmäßige Eingabe- und Ausgabesatztrennzeichen von AWK ist der Zeilenumbruch. Durch Setzen des Trennzeichens ( RS
) für :
Eingabedatensätze vor dem Lesen der Eingabe analysiert AWK automatisch einen durch Doppelpunkte getrennten Namen $PATH
in den konstituierenden Verzeichnisnamen. AWK wird $0
auf jeden vollständigen Datensatz erweitert, die neue Zeile bleibt das Trennzeichen für den Ausgabedatensatz , und es ist keine Schleife gsub
erforderlich.
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 wird häufig zum Parsen von Datensätzen in separate Felder verwendet, es ist jedoch nicht erforderlich, lediglich eine Liste von Verzeichnisnamen zu erstellen.
Dies funktioniert auch für Eingaben mit Leerzeichen (Leerzeichen und Tabulatoren) und mehreren aufeinanderfolgenden Leerzeichen:
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de fg:h'
ab c
de fg
h
Das heißt, es sei denn, Sie veranlassen AWK , den Datensatz neu zu erstellen (siehe unten), ist es kein Problem, Leerzeichen oder Tabulatoren (die Standardfeldtrennzeichen) in der Eingabe zu haben. Ihr enthält PATH
wahrscheinlich keine Leerzeichen auf einem Ubuntu-System, aber wenn dies der Fall ist, funktioniert dies immer noch.
Es ist erwähnenswert, als eine Randnotiz, dass AWK Fähigkeit eine Aufzeichnung als eine Sammlung von Feldern zu interpretieren wird , die für das damit verbundene Problem der Konstruktion eine Tabelle von Verzeichnis Komponenten :
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
Die merkwürdige $1=$1
Aufgabe hat den Zweck, AWK zu zwingen , den Datensatz neu zu erstellen .
(Dies ist wahrscheinlich nützlicher für Fälle, in denen zusätzliche Verarbeitung für die Komponenten ausgeführt werden soll, als für das genaue gezeigte Beispiel des einfachen Druckens der Tabelle.)
jq -Rr 'gsub(":";"\n")' <<<$PATH
So zeigen Sie die Pfade in $ PATH separat an
Dies sind meine bevorzugten Methoden, basierend auf meinen jeweiligen Anwendungsfällen und Bedenken hinsichtlich Kompatibilität und Ressourcennutzung.
tr
Wenn Sie eine schnelle, leicht zu merkende und lesbare Lösung benötigen, wiederholen Sie diese und leiten Sie PATH
sie an translate ( tr
) weiter , um die Doppelpunkte in Zeilenumbrüche umzuwandeln:
echo $PATH | tr : "\n"
Es hat den Nachteil, dass aufgrund der Pipe zwei Prozesse verwendet werden, aber wenn wir nur in ein Terminal hacken, interessiert uns das wirklich?
Wenn Sie eine relativ dauerhafte Lösung .bashrc
für die interaktive Verwendung wünschen , können Sie den folgenden Befehl als Alias verwenden path
, die Lesbarkeit dieser Lösung ist jedoch fraglich:
alias path="echo \"${PATH//:/$'\n'}\""
Wenn das Muster mit '/' beginnt, werden alle Übereinstimmungen des Musters durch eine Zeichenfolge ersetzt. Normalerweise wird nur die erste Übereinstimmung ersetzt.
Der obige Befehl ersetzt den Doppelpunkt mit Zeilenumbrüchen unter Verwendung der Shell-Parametererweiterung von Bash :
${parameter/pattern/string}
Um es zu erklären:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
Viel Glück, wenn Sie sich daran erinnern, wenn Sie nur über die Befehlszeile hacken, wenn Sie es aber nicht geglättet haben.
Alternativ können Sie die folgende Funktion verwenden, wenn Sie einen ziemlich kompatiblen, lesbaren und verständlichen Ansatz verfolgen, der sich auf nichts anderes als die Shell stützt (ich schlage in Ihrem Beispiel vor .bashrc
).
Die folgende Funktion macht das interne (oder Eingabe-) Feldtrennzeichen (IFS) vorübergehend zu einem Doppelpunkt, und wenn ein Array übergeben wird, printf
wird es ausgeführt, bis das Array aufgebraucht ist:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
Diese Methode der Funktion Schöpfung , IFS
und printf
sind für die von Posix vorgesehen, so dass es in den meisten Posix artigen Schalen funktionieren sollte (vor allem Dash, die Ubuntu in der Regel Aliase wie sh
).
Solltest du dafür Python verwenden? Du könntest. Dies ist der kürzeste Python-Befehl, den ich mir vorstellen kann:
python -c "print('\n'.join('${PATH}'.split(':')))"
oder nur Python 3 (und vielleicht besser lesbar?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
Diese sollten auch in jeder normalen Shell-Umgebung funktionieren, solange Sie Python haben.
Diese Lösung ist einfacher als die Java , C , go und awk- Lösungen:
$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
Hier ist eine weitere großartige Möglichkeit:
$ 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
Dazu müssten einige Abhängigkeiten installiert werden:
sudo apt-get install openjdk-8-jdk-headless bsh