Nowa linia w zmiennych bash


9

Próbuję zapisać wiele wierszy w zmiennej bash, ale wydaje się, że to nie działa.

Na przykład, jeśli wymienię /binjeden plik w wierszu i zapiszę go $LS, $LSprzekażę jako standardowe wejście wc, zawsze zwraca 1:

$ ls -1 /bin | wc -l
134
$ LS=$(ls -1 /bin); wc -l <<< $LS
1

Gdy próbuję wyświetlać obraz na ekranie, otrzymuję różne wyniki: echodrukuje wszystkie linie w jednym wierszu, a printfdrukuje tylko pierwszy wiersz:

#!/bin/bash
LS=$(ls -1 /bin)
echo $LS
printf $LS

Więc zmienna bash może zawierać wiele linii?

Odpowiedzi:


15

Musisz go podwoić ( w większości przypadków powinieneś podwoić zmienne ):

echo "$LS"

Ale nie używaj echa do drukowania zawartości zmiennych, zamiast tego użyj printf :

printf '%s\n' "$LS"

1
Żeby uściślić ogólną odpowiedź: printf oczekuje, że łańcuch formatu będzie pierwszym parametrem, dlatego nie widzieli tego, czego się spodziewali. Jeśli chcą zobaczyć nowe wiersze na wyjściu z printf, arbtralnie podzielone na spacje, printf "%s\n" $LSzrobiłyby to.
Jeff Schaller

% LS powinien wynosić $ LS, btw (nie mogłem dokonać tak krótkiej edycji)
Jeff Schaller

Dzięki! Oczywiście działa również z wcinnymi poleceniami:wc -l <<< "$LS"
Wizard79

1
@JeffSchaller: Nie, nie powinieneś cofać cytowania zmiennej w tym przypadku, po prostu użyj, printf '%s\n' "$LS"jeśli chcesz zobaczyć nowy wiersz. Błędne pisanie, naprawione!
cuonglm

Dlaczego nie powinieneś używać echa do drukowania zmiennych?
123

9

Nowe linie są w zmiennej. LS=$(ls -1)ustawia zmienną LSna wynik ls -1(co daje takie same wyniki, jak ls, nawiasem mówiąc, z wyjątkiem sytuacji, gdy wyjście trafia do terminala), minus końcowe znaki nowej linii.

Problem polega na tym, że usuwasz znaki nowej linii podczas drukowania wartości. W skrypcie powłoki $LSnie oznacza „wartości zmiennej LS”, oznacza „wziąć wartość LS, podzielić ją na słowa według IFSi interpretować każde słowo jako wzorzec globalny”. Aby uzyskać wartość LS, musisz napisać "$LS", lub bardziej ogólnie, umieścić $LSmiędzy podwójnymi cudzysłowami.

echo "$LS"wypisuje wartość LS, z wyjątkiem niektórych powłok, które interpretują znaki odwrotnego ukośnika, z wyjątkiem kilku wartości zaczynających się od -.

printf "$LS"wypisuje wartość, o LSile nie zawiera znaku procentu ani ukośnika odwrotnego i (w przypadku większości implementacji) nie zaczyna się od -.

Aby LSdokładnie wydrukować wartość , użyj printf %s "$LS". Jeśli chcesz na końcu nowego wiersza, użyj printf '%s\n' "$LS".

Zauważ, że $(ls)ogólnie nie jest to lista plików w bieżącym katalogu. Działa to tylko wtedy, gdy masz wystarczająco oswojone nazwy plików. Aby uzyskać listę nazw plików (z wyjątkiem plików kropka), trzeba użyć symbolu wieloznacznego: *. Wynikiem jest lista ciągów, a nie ciąg, więc nie można przypisać jej do zmiennej ciąg; możesz użyć zmiennej tablicowej files=(*)w powłokach, które je obsługują (ksh93, bash, zsh).

Aby uzyskać więcej informacji, zobacz Dlaczego mój skrypt powłoki dusi się spacją lub innymi znakami specjalnymi?


printf „$ LS”
ulegałby także analizie

0

Wcześniej wspomniane

printf '%s\n' "$LS"

jest jedynym poprawnym rozwiązaniem.

Pokażę, że inne proponowane rozwiązania, zarówno z, jak echoi printf, po prostu nie działają poprawnie:

$ mkdir t
$ cd t
$ touch \\n
$ LS=$(ls -l)
$ echo "$LS"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12

$ printf "$LS\n"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12

$ printf '%s\n' "$LS"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12 \n
$ ls -l
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12 \n
$ rm \\n
$ cd ..
$ rmdir t
$

(Można również testować V=$(printf 'line0:\\n\\n\nline1.\n') printf '%s\n' "$V"i odmiany.)

Podczas gdy \nw nazwach plików może nie być tak powszechne, zapisz git diffje w zmiennej, a twoje szanse na dosłowność \nwzrosną gwałtownie.


Uwaga, ksha zshtakże wsparcie, print -r -- "$LS"a zshtakże ma echo -E - $LS. cshma echo $LS:qjednak, że nie wypisuje znaku nowej linii, jeśli $ LS jest pusty, a uzyskanie wartości wielowierszowej do $ LS w pierwszej kolejności jest dość trudne w csh.
Stéphane Chazelas,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.