Nie mogę wymyślić, jak wymienić poszczególne ścieżki $PATH
osobno, aby wyglądały tak:
/bin
/usr/bin
/usr/local/bin
itp.
Czy ktoś zna poprawną zmienną do tego?
Nie mogę wymyślić, jak wymienić poszczególne ścieżki $PATH
osobno, aby wyglądały tak:
/bin
/usr/bin
/usr/local/bin
itp.
Czy ktoś zna poprawną zmienną do tego?
Odpowiedzi:
Spróbuj sed
:
$ sed 's/:/\n/g' <<< "$PATH"
Lub tr
:
$ tr ':' '\n' <<< "$PATH"
Lub python
:
$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"
Tutaj wszystkie powyższe zastąpią wszystkie wystąpienia :
nowymi liniami \n
.
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
python -c "print r'$PATH'.replace(':', '\n')"
(stosując surowe ciąg w przypadku ukośniki)
tr
pracował dla mnie (na Mac, BTW). Dzięki.
.bash_profile
, dodaj to w ten sposób:alias path='tr ":" "\n" <<< "$PATH"'
Użyj rozszerzenia parametrów bash :
echo "${PATH//:/$'\n'}"
Wszystko to zastępuje :
w $PATH
nową linią ( \n
) i drukuje wynik. Treść $PATH
pozostaje niezmieniona.
Jeśli chcesz tylko zastąpić pierwszy :
, usuń drugi ukośnik:echo -e "${PATH/:/\n}"
${parameter/pattern/string}
Korzystanie z IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
zawiera znaki, na których bash dzieli się, więc IFS
z :
powoduje, że bash dzieli rozszerzenie $PATH
na :
. printf
zapętla argumenty nad ciągiem formatu, aż argumenty zostaną wyczerpane. Musimy wyłączyć globbing (rozwijanie symboli wieloznacznych) za pomocą set -f
, aby symbole wieloznaczne w nazwach katalogów PATH nie były rozwijane.
Używanie xargs
:
xargs -n1 -d: <<< $PATH
Od 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
byłyby zbędne, czy to nie ma znaczenia?
echo $PATH | xargs -n1 -d:
zrobi to samo dla ciebie, ale będziesz używał jeszcze jednej powłoki. Pierwszy oceni echo $PATH
i przesyła dane wyjściowe do następnej powłoki, aby wykonać resztę.
Oto odpowiednik w 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
Oto kilka innych podejść. Używam PATH
z katalogami zawierającymi ukośniki odwrotne, spacje, a nawet nową linię, aby pokazać, że powinny działać ze wszystkim (oprócz tego, cut
który zawodzi na nowych liniach):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
Niektóre sposoby Perla:
$ perl -pe 's/:/\n/g' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Te -p
środki „wydrukować każdą linię wejściowego po zastosowaniu skryptu podane przez -e
”. Skrypt używa operatora podstawienia ( s/oldnew/
) do zastąpienia wszystkich :
znakami nowej linii.
$ perl -lne 'print for split /:/' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
-l
Dodaje nowej linii do każdej print
rozmowy. Tutaj skrypt dzieli swój wkład, :
a następnie zapętla każdy podzielony element i drukuje go.
$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Te -a
marki perl
zachowują się jak awk
: będzie podzielić każdy z jego linii wejściowych od charakteru danej przez -F
(tak :
, tutaj) i zapisać wynik w tablicy @F
. $"
Jest specjalną zmienną Perl, „Wykaz separatora”, którego wartość jest drukowany pomiędzy poszczególnymi elementami listy drukowanej. Tak więc ustawienie go na nową linię spowoduje print @list
wydrukowanie każdego elementu, @list
a następnie nowej linii. Tutaj używamy go do drukowania @F
.
$ perl -F: -ane 'print join "\n", @F' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Taki sam pomysł jak powyżej, tylko mniej golfa. Zamiast używać $"
, jawnie join
wprowadzamy tablicę z nowymi liniami, a następnie drukujemy.
Proste grep
z magią PCRE:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Te -o
marki grep
wydrukować tylko część dopasowanie każdej linii, więc każdy mecz jest drukowany na oddzielnej linii. -P
Umożliwia pcre (pcre). Wyrażenie regularne szuka ciągów znaków innych niż :
( [^:]+
), które następują na początku wiersza ( ^
) lub :
znaku. Jest \K
to sztuczka PCRE, która oznacza „odrzuć wszystko pasujące przed tym punktem” i jest używana tutaj, aby uniknąć drukowania :
również.
I cut
rozwiązanie (to nie działa na nowych liniach, ale może radzić sobie z odwrotnymi ukośnikami i spacjami):
$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Zastosowano następujące opcje, -d:
które ustawiają ogranicznik wejściowy na :
, -f 1-
co oznacza drukowanie wszystkich pól (od 1 do końca) i --output-delimiter=$'\n'
które ustawiają, no cóż, ogranicznik wyjściowy. Jest $'\n'
to cytat ANSI C i jest sposobem na wydrukowanie znaku nowej linii w powłoce.
We wszystkich powyższych przykładach używam tutaj<<<
operatora string ( ) bash (i niektórych innych powłok ), aby przekazać ciąg znaków jako dane wejściowe do programu. Więc command <<<"foo"
jest równoważna echo -n "foo" | command
. Zauważ, że zawsze cytuję "$PATH"
, bez cytatów, skorupa zjadłaby znak nowej linii.
@ 7stud podał inne podejście w komentarzach, które jest po prostu zbyt dobre, aby nie zawierać:
$ perl -0x3a -l012 -pe '' <<<"$PATH"
To się nazywa golf . -0
Określa separator rekordu wejściowego jako liczby ósemkowej lub szesnastkowej. To właśnie definiuje „linię”, a jej wartością domyślną jest \n
znak nowej linii. Tutaj ustawiamy go na :
co jest x3a
w hex (TRY printf '\x3a\n'
). -l
Robi trzy rzeczy. Najpierw usuwa się separator rekordu wejściowego ( $/
) z końca każdej linii, skutecznie usuwając :
tutaj, a po drugie, to ustawia separator rekordów wyjściowych ( $\
), aby cokolwiek ósemkowe lub wartość hex jest przekazywana ( 012
jest \n
). Jeśli $\
jest zdefiniowane, jest dodawane na końcu każdego print
połączenia, więc spowoduje to dołączenie nowego wiersza do każdego print
.
-pe
Wola p rukuj każdą linię wejściowego po zastosowaniu skryptu podane przez -e
. Tutaj nie ma skryptu, ponieważ cała praca jest wykonywana przez flagi opcji, jak opisano powyżej!
perl -0x3a -l012 -pe '' <<<$PATH
. Objaśnienie: -0
ustawia separator rekordów wejściowych (określony w notacji szesnastkowej / ósemkowej, x3A jest dwukropkiem), -l
robi dwie rzeczy: 1) przecina separator rekordów wejściowych, 2) ustawia separator rekordów wyjściowych, jeśli jest określony (w notacji ósemkowej , 012 to nowa linia). A -p
odciski LOOP OUT wartości $ _, który będzie każdy wiersz przeczytać w.
-F
informację. Używam w -F
połączeniu z -an
od lat, nigdy nie zdawałem sobie sprawy, że ten sugeruje inne. Nawiasem mówiąc, widziałem, jak Serg wspomniał o Code Golf , ale myślę, że spodoba ci się także Unix i Linux, jeśli lubisz takie rzeczy.
-l
dodaje również separator rekordów wyjściowych podany na końcu każdego wywołania drukowania. W rzeczywistości print zawsze dodaje separator rekordu wyjściowego $/
, na końcu łańcucha - jeśli separator rekordu wyjściowego jest zdefiniowany. Domyślnie jest undef. Więc -l
jus ustawia $/
, a to powoduje, że print dodaje nowy wiersz na końcu łańcucha.
Ponieważ wszystkie języki skryptowe są już zajęte, wybiorę C. Używanie funkcji jest dość łatwe get_env()
(patrz dokumentacja biblioteki GNU C ). Reszta to po prostu manipulacja postaciami
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
Ale także dlatego, że „dlaczego nie”, oto alternatywna wersja Pythona za pomocą argumentów wiersza poleceń sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
Ruby nie jest domyślnie wyposażony w Ubuntu, w przeciwieństwie do kompilatora C i interpretera Pythona, ale jeśli kiedykolwiek go użyjesz, rozwiązaniem w Ruby byłoby:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Jak sugeruje 7stud (Dziękuję bardzo!) W komentarzach , można to również skrócić
ruby -F: -ane 'puts $F' <<<$PATH
i w ten sposób
ruby -0072 -ne 'puts chomp' <<<$PATH
Możemy użyć split()
funkcji do rozbicia linii odczytanej na tablicę i użyć for-each
pętli do wydrukowania każdego elementu w osobnej linii.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
automatycznie drukuje elementy tablicy na osobnych liniach! Możesz także ustawić przełączniki na podział: ruby -F: -ane 'puts $F' <<<$PATH
Objaśnienie: -F
ustawia $;
na określony znak, który jest domyślnym separatorem używanym przez String :: split ($; ma domyślną wartość zero, która dzieli się na białe znaki). -a
wywołuje $ _. split, gdzie $ _ jest linią wczytywaną za pomocą gets ()) i przypisuje wynikową tablicę do $F
.
-F
flaga - zaczynam od Ruby, więc robię rzeczy nieco prymitywnie.
ruby -0072 -ne 'puts chomp' <<<$PATH
. Objaśnienie: -0
ustawia separator rekordów wejściowych (określ znak w formacie ósemkowym; 072 to dwukropek). Ruby zatrudnia $ _ w sposób podobny do Perla. Metoda gets () (używana w -n
pętli) ustawia $ _ na bieżący wiersz, który jest wczytywany. chomp()
Bez argumentu chomps $ _. Nadal lubię twój. :)
-F
flagą, jest krótszy. Jeśli to zrobisz, echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
to powie mi, że to 271 bajtów, ale ten z liczbą ósemkową to 276. To oczywiście dotyczy całego polecenia, jeśli weźmiemy pod uwagę, że sam kod puts $F
jest wyraźnie krótszy. :) Przy okazji, czy wiesz o Code Golf ? Jest to strona z rozwiązaniami do programowania łamigłówek w jak najkrótszej liczbie bajtów. Jest z tym związane pytanie: codegolf.stackexchange.com/q/96334/55572
Prawdopodobnie jedynym sposobem, o którym nie wspomniano, jest sposób, w jaki używam go od lat:
echo $PATH | tr ":" "\n"
więc w swoim .profile lub .bash_profile lub czymkolwiek możesz dodać:
alias path='echo $PATH | tr ":" "\n"'
Potrzebujemy więcej Java!
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
Zapisz to GetPathByLine.java
i skompiluj używając:
javac GetPathByLine.java
Biegnij z:
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(':')]"
Przez awk.
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
Poprzez python.
$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
for i in line.split(":"):
print(i)'
Zauważ, że wcięcie jest bardzo ważne w Pythonie.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
kiedy możesz po prostu użyć input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
Używam „Bash Path Functions” Stephena Collyera (zobacz jego artykuł w Linux Journal ). Pozwala mi to na użycie „listy oddzielonych dwukropkami” jako typu danych w programowaniu powłoki. Na przykład mogę utworzyć listę wszystkich katalogów w bieżącym katalogu, wykonując:
dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done
Następnie listpath -p dirs
tworzy listę.
Wyjaśnienie dotyczące odpowiedzi @Cyrus
echo "${PATH//:/$'\n'}"
Uwagi:
Cytowanie ANSI-C - wyjaśnia $ 'some \ ntext'
Rozszerzenie parametru powłoki - wyjaśnia $ {parametr / wzór / ciąg}, Jeśli wzorzec zaczyna się od „/”, wszystkie dopasowania wzorca są zastępowane ciągiem.
Więc mamy:
Innym sposobem AWK jest traktowanie każdego katalogu jako osobnego rekordu , a nie oddzielnego pola .
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
Uważam tę składnię za szczególnie intuicyjną. Ale jeśli chcesz, możesz go skrócić, czyniąc print $0
domniemaną (jest to akcja domyślna i 1
ocenia na prawdę, co powoduje, że jest wykonywana dla każdej linii):
awk 'BEGIN{RS=":"} 1' <<<"$PATH"
Domyślnym separatorem rekordów wejściowych i wyjściowych AWK jest nowa linia (podział wiersza). Ustawiając separator rekordów wejściowych ( RS
) na :
przed odczytem danych wejściowych, AWK automatycznie analizuje separator dwukropka $PATH
w jego stałych nazwach katalogów. AWK rozwija się $0
do każdego całego rekordu, nowy wiersz pozostaje separatorem rekordów wyjściowych i nie wymaga zapętlania ani gsub
jest potrzebny.
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 jest często używany do parsowania rekordów w oddzielnych polach, ale nie ma takiej potrzeby, aby zbudować listę nazw katalogów.
Działa to nawet w przypadku danych wejściowych zawierających spacje (spacje i tabulatory), a nawet wielu kolejnych spacji:
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de fg:h'
ab c
de fg
h
Oznacza to, że jeśli nie spowoduje to odbudowania rekordu przez AWK (patrz poniżej), nie ma problemu z wprowadzaniem spacji lub tabulatorów (domyślnych separatorów pól) na wejściu. Twój PATH
prawdopodobnie nie zawiera spacji w systemie Ubuntu, ale jeśli tak, nadal będzie działać.
Na marginesie warto wspomnieć, że zdolność AWK do interpretowania rekordu jako zbioru pól staje się przydatna w powiązanym problemie tworzenia tabeli składników katalogu :
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
Dziwne $1=$1
zadanie ma na celu zmuszenie AWK do odbudowania rekordu .
(Jest to prawdopodobnie bardziej przydatne w przypadkach, w których należy wykonać dodatkowe przetwarzanie komponentów, niż w dokładnym pokazanym przykładzie po prostu wydrukowania tabeli).
jq -Rr 'gsub(":";"\n")' <<<$PATH
Jak wyświetlać ścieżki w $ PATH osobno
Są to moje preferowane sposoby robienia tego w oparciu o moje odpowiednie przypadki użycia i obawy dotyczące zgodności i wykorzystania zasobów.
tr
Po pierwsze, jeśli potrzebujesz szybkiego, łatwego do zapamiętania i czytelnego rozwiązania, po prostu wykonaj echo PATH
i potokuj go, aby tłumaczyć ( tr
), aby przekształcić dwukropki w nowe linie:
echo $PATH | tr : "\n"
Ma to tę wadę, że używa dwóch procesów z powodu potoku, ale jeśli po prostu hakujemy terminal, czy naprawdę nas to obchodzi?
Jeśli chcesz mieć dość trwałe rozwiązanie .bashrc
interaktywne, możesz użyć aliasu następującego polecenia path
, ale jego czytelność jest wątpliwa:
alias path="echo \"${PATH//:/$'\n'}\""
Jeśli wzorzec zaczyna się od „/”, wszystkie dopasowania wzorca są zastępowane ciągiem. Zwykle tylko pierwszy mecz jest zastępowany.
Powyższe polecenie zastępuje dwukropek nowymi liniami przy użyciu rozszerzenia parametrów powłoki Basha :
${parameter/pattern/string}
Aby to wyjaśnić:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
Powodzenia, gdy pamiętasz o tym, gdy hakujesz w wierszu poleceń, jeśli jeszcze tego nie zrobiłeś.
Alternatywnie, dość kompatybilne, czytelne i zrozumiałe podejście, które nie opiera się na niczym innym niż powłoka, to skorzystaj z następującej funkcji (sugeruję w twoim .bashrc
.)
Poniższa funkcja tymczasowo przekształca wewnętrzny (lub wejściowy) separator pól w dwukropek, a gdy podana jest tablica, jest printf
ona wykonywana, dopóki tablica nie zostanie zużyta:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
Ta metoda tworzenia funkcji , IFS
i printf
są przewidziane posix, więc powinien działać w większości POSIX jak powłok (zwłaszcza Dash, które instalacyjne? Zwykle aliasami sh
).
Czy powinieneś do tego użyć Pythona? Mógłbyś. To jest najkrótsza komenda Pythona, o której mogę pomyśleć:
python -c "print('\n'.join('${PATH}'.split(':')))"
lub tylko Python 3 (a może bardziej czytelny?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
Powinny one również działać w każdym zwykłym środowisku powłoki, o ile masz Python.
To rozwiązanie jest prostsze niż Java , C , go i awk :
$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
Oto kolejna świetna możliwość:
$ 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
Wymagałoby to zainstalowania niektórych zależności:
sudo apt-get install openjdk-8-jdk-headless bsh