@JohnM - Właśnie próbowałem przypisania heredoc z pojedynczym cudzysłowem 'EOF', ze ` in the content: if the second line has znakami ucieczki z komendami cd`, zwracam: " .sh: linia X: cd: polecenie nie znaleziono "; ale jeśli podwójnie zacytuję "EOF"; wtedy zmienne bash ${A}nie są zachowywane jako ciągi znaków (są one rozwijane); ale potem zachowywane są podziały wierszy - i nie mam problemu z uruchomieniem polecenia cdw drugim wierszu ( i zarówno „EOF”, jak i „EOF” wydają się dobrze grać z eval, do uruchamiania zestawu poleceń przechowywanych w zmienna łańcuchowa ). Twoje zdrowie!
sdaau
1
... i aby dodać do mojego poprzedniego komentarza: komentarze bash „#” w "EOF"zmiennej podwójnie qouted , jeśli zostanie wywołane przez eval $VAR, spowoduje skomentowanie całej reszty skryptu, ponieważ tutaj $ VAR będzie widoczny jako pojedynczy wiersz ; aby móc używać #komentarzy bash w skrypcie wielowierszowym, podwójny cudzysłów również zmienny w eval call: ewaluacji „$ VAR”.
sdaau
@ sdaau: Miałem problemy z evaltymi metodami, ale nie wyśledziłem go, ponieważ był on częścią jakiegoś pakietu, który zawiera evalpewne zmienne zdefiniowane w jego pliku konfiguracyjnym. Komunikat o błędzie: /usr/lib/network/network: eval: line 153: syntax error: unexpected end of file. Właśnie przeszedłem na inne rozwiązanie.
Golar Ramblar,
Odpowiedzi:
515
Można uniknąć niepotrzebnego użycia cati obsługi niedopasowane cytaty lepiej z tym:
Jeśli chcesz użyć wcięcia dla czytelności w kodzie źródłowym, użyj myślnika po mniej niż. Wcięcie należy wykonać tylko przy użyciu tabulatorów (bez spacji).
Jeśli zamiast tego chcesz zachować tabulatory w treści wynikowej zmiennej, musisz usunąć tabulatory z IFS. Znacznik końcowy tutaj doc ( EOF) nie może być wcięty.
Karty można wstawiać w wierszu polecenia, naciskając Ctrl- VTab. Jeśli używasz edytora, w zależności od tego, który może również działać lub może być konieczne wyłączenie funkcji, która automatycznie konwertuje tabulatory na spacje.
Myślę, że warto wspomnieć, że jeśli masz set -o errexit(aka set -e) w swoim skrypcie i użyjesz go, to zakończy skrypt, ponieważ readzwraca niezerowy kod powrotu, gdy osiągnie EOF.
Mark Byers
14
@MarkByers: To jeden z powodów, dla których nigdy nie używam set -ei zawsze odradzam jego użycie. Zamiast tego lepiej jest użyć odpowiedniej obsługi błędów. trapjest twoim przyjacielem. Inni przyjaciele: elsei ||między innymi.
Wstrzymano do odwołania.
7
Czy catw takim przypadku unikanie naprawdę jest tego warte? Przypisywanie heredoc do zmiennej za pomocą catjest dobrze znanym idiomem. Jakoś użycie readzaciemnia rzeczy dla małych korzyści imho.
Gregory Pakosz
6
@ulidtko To dlatego, że nie ma spacji między di pusty ciąg; bashzapada -rd''się tak, że nigdy -rdprzedtem readnie widzi swoich argumentów, więc VARjest traktowany jak argument do -d.
chepner
6
W tym formacie readzwróci niezerowy kod wyjścia. To sprawia, że ta metoda nie jest idealna w skrypcie z włączoną funkcją sprawdzania błędów (np set -e.).
Szwajcarski
245
Użyj $ (), aby przypisać wynik catswojej zmiennej w następujący sposób:
VAR=$(cat <<'END_HEREDOC'
abc'asdf"
$(dont-execute-this)
foo"bar"''
END_HEREDOC
)
# this will echo variable with new lines intact
echo "$VAR"
# this will echo variable without new lines (changed to space character)
echo $VAR
Pamiętaj, by oddzielić END_HEREDOC od pojedynczych cudzysłowów.
Zauważ, że ogranicznik heredoc kończący END_HEREDOCmusi znajdować się sam na linii (stąd nawias kończący znajduje się w następnej linii).
Właściwie to w niektórych okolicznościach przepuszcza cytaty. Z łatwością udało mi się to zrobić w Perlu ...
Neil,
32
+1. To jest najbardziej czytelne rozwiązanie, przynajmniej dla moich oczu. Pozostawia nazwę zmiennej po lewej stronie, zamiast osadzać ją w poleceniu read.
Clayton Stanley,
12
PSA: pamiętaj, że zmienna musi być cytowana, aby zachować nowe wiersze. echo "$VAR"zamiast echo $VAR.
sevko
7
To jest miłe z ashOpenWRT, gdzie readnie obsługuje -d.
David Ehrmann
3
Z powodów, których nie mogę pojąć, nie powiedzie się to z powodu „nieoczekiwanego błędu EOF”, jeśli w heredoc masz niesparowany backstick.
Radon Rosborough,
79
jest to odmiana metody Dennisa, wygląda bardziej elegancko w skryptach.
definicja funkcji:
define(){ IFS='\n' read -r -d '' ${1}|| true;}
stosowanie:
define VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
echo "$VAR"
cieszyć się
ps utworzył wersję „pętli odczytu” dla powłok, które nie obsługują read -d. powinny pracować z set -eui niesparowanych backticks , ale nie badanych bardzo dobrze:
To wydaje się działać tylko powierzchownie. Funkcja definiująca zwróci status 1 i nie jestem pewien, co należy poprawić.
fny
1
Jest to również lepsze niż zaakceptowana odpowiedź, ponieważ można ją zmodyfikować tak, aby obsługiwała POSIX sh oprócz bash ( readpętla w funkcji, aby uniknąć -d ''bashizmu niezbędnego do zachowania nowych linii).
ELLIOTTCABLE,
W przeciwieństwie do opcji cat-in-a-shell, działa to z niesparowanymi backtickami w heredoc. Dziękuję Ci!
Radon Rosborough,
To rozwiązanie działa z set -eustawionym zestawem, a wybrana odpowiedź nie. Wydaje się, że http://unix.stackexchange.com/a/265151/20650
dzieje
2
@fny ps status powrotu został już naprawiony
ttt
36
VAR=<<END
abc
END
nie działa, ponieważ przekierowujesz stdin do czegoś, co go nie obchodzi, a mianowicie do zadania
export A=`cat <<END
sdfsdf
sdfsdf
sdfsfds
END
`; echo $A
działa, ale jest tam back-tic, który może powstrzymać cię od korzystania z tego. Ponadto naprawdę powinieneś unikać używania odwrotnych wskazówek, lepiej jest użyć notacji zastępowania poleceń $(..).
export A=$(cat <<END
sdfsdf
sdfsdf
sdfsfds
END
); echo $A
Zaktualizowałem moje pytanie, aby zawierało $ (plik wykonywalny). Jak zachować nowe wiersze?
Neil
2
@ l0st3d: Tak blisko ... Użyj $(cat <<'END'zamiast tego. @Neil: Ostatnia nowa linia nie będzie częścią zmiennej, ale reszta zostanie zachowana.
ephemient
1
Wygląda na to, że nie zachowano żadnych nowych linii. W powyższym przykładzie widzę: „sdfsdf sdfsdf sdfsfds” ... ah! Ale pisząc echo "$A"(tj. Umieszczając $ A w podwójnych cudzysłowach) i widzisz nowe linie!
Darren Cook
1
@Darren: aha! Zauważyłem problem nowego wiersza i użycie cudzysłowu wokół zmiennej wyjściowej naprawia problem. dzięki!
javadba
1
Co ciekawe, ze względu na dziwactwo pierwszym przykładzie, w celowniku można użyć go do prowizorycznych bloków komentarzy jak ten: REM=<< 'REM' ... comment block goes here ... REM. Lub bardziej zwięźle, : << 'REM' .... Gdzie „REM” może być czymś w rodzaju „UWAGI” lub „SCRATCHPAD” itp.
Beejor,
34
Nadal nie ma rozwiązania, które zachowuje nowe linie.
To nieprawda - prawdopodobnie echo wprowadza Cię w błąd:
Naprawdę jest to sposób działania cytowania zmiennej. Bez cudzysłowów wstawi je jako różne parametry, z ograniczeniem miejsca, natomiast w cudzysłowach cała zawartość zmiennej będzie traktowana jako jeden argument
Czipperz
11
Opierając się na odpowiedzi Neila , często nie potrzebujesz w ogóle var, możesz użyć funkcji w taki sam sposób jak zmienną i jest znacznie łatwiejszy do odczytania niż rozwiązania wbudowane lub readoparte na bazie .
$ complex_message(){
cat <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
}
$ echo "This is a $(complex_message)"
This is a abc'asdf"
$(dont-execute-this)
foo"bar"''
Kiedy wypróbowałem pierwszą metodę, wydaje się, że między liniami nie ma terminatorów linii. Czy musi to być jakaś konfiguracja na moim komputerze z systemem Linux?
Kemin Zhou
Prawdopodobnie oznacza to, że podczas echa zmiennej nie wstawiłeś cudzysłowów ... Spróbuj tak:echo "$VAR"
Brad Parks
1
Przekonałem się, że muszę przeczytać ciąg znaków z wartością NULL, więc oto rozwiązanie, które przeczyta wszystko, co na niego rzucisz. Chociaż jeśli faktycznie masz do czynienia z NULL, będziesz musiał sobie z tym poradzić na poziomie heksów.
Dzięki odpowiedzi dimo414 pokazuje to, jak działa jego świetne rozwiązanie, a także pokazuje, że w tekście można łatwo umieszczać cytaty i zmienne:
przykładowe wyjście
$ ./test.sh
The text from the example function is:Welcome dev:Would you "like" to know how many 'files' there are in/tmp?There are " 38" files in/tmp, according to the "wc" command
test.sh
#!/bin/bashfunction text1(){
COUNT=$(\ls /tmp | wc -l)
cat <<EOF
$1 Would you "like" to know how many 'files' there are in/tmp?There are "$COUNT" files in/tmp, according to the "wc" command
EOF
}function main(){
OUT=$(text1 "Welcome dev:")
echo "The text from the example function is: $OUT"}
main
Byłoby interesujące zobaczyć niedopasowany cytat w tekście, aby zobaczyć, jak sobie z tym radzi. Może „Nie wystrasz się, są pliki„ $ COUNT ”, więc apostrof / pojedynczy cudzysłów może sprawić, że wszystko będzie interesujące.
dragon788
-10
$TEST="ok"
read MYTEXT <<EOT
this bash trick
should preserve
newlines $TEST
long live perl
EOT
echo -e $MYTEXT
'EOF'
, ze` in the content: if the second line has
znakami ucieczki z komendami cd`, zwracam: " .sh: linia X: cd: polecenie nie znaleziono "; ale jeśli podwójnie zacytuję"EOF"
; wtedy zmienne bash${A}
nie są zachowywane jako ciągi znaków (są one rozwijane); ale potem zachowywane są podziały wierszy - i nie mam problemu z uruchomieniem poleceniacd
w drugim wierszu ( i zarówno „EOF”, jak i „EOF” wydają się dobrze grać zeval
, do uruchamiania zestawu poleceń przechowywanych w zmienna łańcuchowa ). Twoje zdrowie!"EOF"
zmiennej podwójnie qouted , jeśli zostanie wywołane przezeval $VAR
, spowoduje skomentowanie całej reszty skryptu, ponieważ tutaj $ VAR będzie widoczny jako pojedynczy wiersz ; aby móc używać#
komentarzy bash w skrypcie wielowierszowym, podwójny cudzysłów również zmienny weval call:
ewaluacji „$ VAR”.eval
tymi metodami, ale nie wyśledziłem go, ponieważ był on częścią jakiegoś pakietu, który zawieraeval
pewne zmienne zdefiniowane w jego pliku konfiguracyjnym. Komunikat o błędzie:/usr/lib/network/network: eval: line 153: syntax error: unexpected end of file
. Właśnie przeszedłem na inne rozwiązanie.Odpowiedzi:
Można uniknąć niepotrzebnego użycia
cat
i obsługi niedopasowane cytaty lepiej z tym:Jeśli nie podasz zmiennej podczas echa, znaki nowej linii zostaną utracone. Cytując to zachowuje je:
Jeśli chcesz użyć wcięcia dla czytelności w kodzie źródłowym, użyj myślnika po mniej niż. Wcięcie należy wykonać tylko przy użyciu tabulatorów (bez spacji).
Jeśli zamiast tego chcesz zachować tabulatory w treści wynikowej zmiennej, musisz usunąć tabulatory z
IFS
. Znacznik końcowy tutaj doc (EOF
) nie może być wcięty.Karty można wstawiać w wierszu polecenia, naciskając Ctrl- V Tab. Jeśli używasz edytora, w zależności od tego, który może również działać lub może być konieczne wyłączenie funkcji, która automatycznie konwertuje tabulatory na spacje.
źródło
set -o errexit
(akaset -e
) w swoim skrypcie i użyjesz go, to zakończy skrypt, ponieważread
zwraca niezerowy kod powrotu, gdy osiągnie EOF.set -e
i zawsze odradzam jego użycie. Zamiast tego lepiej jest użyć odpowiedniej obsługi błędów.trap
jest twoim przyjacielem. Inni przyjaciele:else
i||
między innymi.cat
w takim przypadku unikanie naprawdę jest tego warte? Przypisywanie heredoc do zmiennej za pomocącat
jest dobrze znanym idiomem. Jakoś użycieread
zaciemnia rzeczy dla małych korzyści imho.d
i pusty ciąg;bash
zapada-rd''
się tak, że nigdy-rd
przedtemread
nie widzi swoich argumentów, więcVAR
jest traktowany jak argument do-d
.read
zwróci niezerowy kod wyjścia. To sprawia, że ta metoda nie jest idealna w skrypcie z włączoną funkcją sprawdzania błędów (npset -e
.).Użyj $ (), aby przypisać wynik
cat
swojej zmiennej w następujący sposób:Pamiętaj, by oddzielić END_HEREDOC od pojedynczych cudzysłowów.
Zauważ, że ogranicznik heredoc kończący
END_HEREDOC
musi znajdować się sam na linii (stąd nawias kończący znajduje się w następnej linii).Dzięki
@ephemient
za odpowiedź.źródło
echo "$VAR"
zamiastecho $VAR
.ash
OpenWRT, gdzieread
nie obsługuje-d
.jest to odmiana metody Dennisa, wygląda bardziej elegancko w skryptach.
definicja funkcji:
stosowanie:
cieszyć się
ps utworzył wersję „pętli odczytu” dla powłok, które nie obsługują
read -d
. powinny pracować zset -eu
i niesparowanych backticks , ale nie badanych bardzo dobrze:źródło
read
pętla w funkcji, aby uniknąć-d ''
bashizmu niezbędnego do zachowania nowych linii).set -e
ustawionym zestawem, a wybrana odpowiedź nie. Wydaje się, żehttp://unix.stackexchange.com/a/265151/20650
nie działa, ponieważ przekierowujesz stdin do czegoś, co go nie obchodzi, a mianowicie do zadania
działa, ale jest tam back-tic, który może powstrzymać cię od korzystania z tego. Ponadto naprawdę powinieneś unikać używania odwrotnych wskazówek, lepiej jest użyć notacji zastępowania poleceń
$(..)
.źródło
$(cat <<'END'
zamiast tego. @Neil: Ostatnia nowa linia nie będzie częścią zmiennej, ale reszta zostanie zachowana.echo "$A"
(tj. Umieszczając $ A w podwójnych cudzysłowach) i widzisz nowe linie!REM=<< 'REM' ... comment block goes here ... REM
. Lub bardziej zwięźle,: << 'REM' ...
. Gdzie „REM” może być czymś w rodzaju „UWAGI” lub „SCRATCHPAD” itp.To nieprawda - prawdopodobnie echo wprowadza Cię w błąd:
echo $VAR # strips newlines
echo "$VAR" # preserves newlines
źródło
Opierając się na odpowiedzi Neila , często nie potrzebujesz w ogóle var, możesz użyć funkcji w taki sam sposób jak zmienną i jest znacznie łatwiejszy do odczytania niż rozwiązania wbudowane lub
read
oparte na bazie .źródło
Tablica jest zmienną, więc w takim przypadku plik map będzie działał
Następnie możesz wydrukować w ten sposób
źródło
przypisz wartość heredoc do zmiennej
używany jako argument polecenia
źródło
echo "$VAR"
Przekonałem się, że muszę przeczytać ciąg znaków z wartością NULL, więc oto rozwiązanie, które przeczyta wszystko, co na niego rzucisz. Chociaż jeśli faktycznie masz do czynienia z NULL, będziesz musiał sobie z tym poradzić na poziomie heksów.
$ cat> read.dd.sh
Dowód:
Przykład HEREDOC (z ^ J, ^ M, ^ I):
źródło
Dzięki odpowiedzi dimo414 pokazuje to, jak działa jego świetne rozwiązanie, a także pokazuje, że w tekście można łatwo umieszczać cytaty i zmienne:
przykładowe wyjście
test.sh
źródło
źródło