Rozważ dwie próbki powłoki
$ ls
myDoc.html
SomeDirectory
someDoc.txt
i
$ echo $(ls)
myDoc.html SomeDirectory someDoc.txt
Pierwszy wykonuje, ls
który, jak rozumiem, dołącza zawartość bieżącego katalogu roboczego do stdout
pliku (co wyświetla terminal). Czy to jest poprawne?
Drugi pobiera wartość ls
polecenia (co oznacza zawartość bieżącego katalogu roboczego) i drukuje go do stdout
pliku. Czy to jest poprawne?
Dlaczego te dwa polecenia dają różne wyniki?
ls
sam w sobie nie daje wielu pozycji w wierszu?echo *
?Odpowiedzi:
Po uruchomieniu tego polecenia:
terminal wyświetla wynik działania
ls
.Po uruchomieniu tego polecenia:
powłoka przechwytuje dane wyjściowe
$(ls)
i dokonuje na nich podziału słów . Przy ustawieniu domyślnymIFS
oznacza to, że wszystkie sekwencje białych znaków, w tym znaki nowego wiersza, są zastępowane jednym pustym miejscem. Dlatego wynik działaniaecho $(ls)
pojawia się w jednym wierszu.Aby uzyskać zaawansowaną dyskusję na temat podziału słów, zobacz często zadawane pytania Grega .
Pomijanie podziału słów
Powłoka nie wykonuje dzielenia słów na ciągi w cudzysłowie. W ten sposób możesz ukryć dzielenie słów i zachować wieloliniowe wyjście za pomocą:
ls
i wyjście wielowierszoweByć może zauważyłeś, że
ls
czasami drukuje więcej niż jeden plik w linii:Jest to ustawienie domyślne, gdy dane wyjściowe są przesyłane
ls
do terminala. Gdy dane wyjściowe nie idą bezpośrednio do terminala,ls
zmienia się domyślnie na jeden plik w linii:To zachowanie jest udokumentowane w
man ls
.Kolejna subtelność: zastępowanie poleceń i końcowe znaki nowej linii
$(...)
jest podstawieniem polecenia, a powłoka usuwa końcowe znaki nowego wiersza z wyjścia podstawienia polecenia . Zwykle nie jest to zauważalne, ponieważ domyślnieecho
dodaje jeden nowy wiersz na końcu danych wyjściowych. Tak więc, jeśli stracisz jedną nową linię od końca$(...)
i zyskasz jedną zecho
, nie ma zmiany. Jeśli jednak dane wyjściowe polecenia kończą się co najmniej 2 znakami nowej linii, aecho
dodaje tylko jeden znak z powrotem, w wynikach brakuje jednego lub więcej znaków nowej linii. Jako przykład możemy użyćprintf
do generowania końcowych znaków nowego wiersza. Zauważ, że oba poniższe polecenia, pomimo różnej liczby znaków nowej linii, dają takie same dane wyjściowe z jednej pustej linii:To zachowanie jest udokumentowane w
man bash
.Kolejna niespodzianka: dwukrotne rozwinięcie nazwy ścieżki
Utwórzmy trzy pliki:
Zaobserwować różnicę między
ls file?
iecho $(ls file?)
:W przypadku
echo $(ls file?)
glob plikufile?
jest dwukrotnie rozszerzany , powodując, że nazwy plikówfile1
ifile2
pojawia się dwukrotnie na wyjściu. Jest tak, ponieważ, jak wskazuje Jeffiekins, interpretacja ścieżki jest wykonywana najpierw przez powłokę przedls
uruchomieniem, a następnie ponownie przedecho
uruchomieniem.Drugie rozszerzenie nazwy ścieżki można pominąć, jeśli użyjemy podwójnych cudzysłowów:
źródło
isatty
możesz sprawdzić, czy stdout jest tty, ls używa tego do określenia, czy użyć kolorów, czy nie.$( )
faktycznie zapewniają barierę składni, więc nie trzeba interpolować?$()
zapewnia barierę składni.echo
polecenie rozwinie symbol wieloznaczny . Na przykład, jeślils
zwraca plik? plik1 plik2 , a następnieecho $(ls)
zwróci plik? plik1 plik2 plik1 plik2 .echo
nie rozwija symboli wieloznacznych; powłoka robi to przed przekazaniem wynikowego rozszerzenia jako argumentów doecho
.ls
ma świadomość, czy wysyła dane wyjściowe do terminala, czy nie.Wykonanie
ls
w wierszu polecenia zapisze na twoim pseudo-tty. Przekierowanie wyjścials
zwykle nie będzie pseudo-tty ils
sformatuje wyjście inaczej.źródło