Come aggiungere nuove righe nelle variabili nello script bash


Risposte:


73

In bashpuoi usare la sintassi

str=$'Hello World\n===========\n'

Le virgolette singole precedute da a $sono una nuova sintassi che consente di inserire sequenze di escape nelle stringhe.

Inoltre, printfbuiltin consente di salvare l'output risultante in una variabile

printf -v str 'Hello World\n===========\n'

Entrambe le soluzioni non richiedono una subshell.

Se di seguito è necessario stampare la stringa, utilizzare virgolette doppie, come nell'esempio seguente:

echo "$str"

perché quando si stampa la stringa senza virgolette, la nuova riga viene convertita in spazi.


1
Come si str=$'Hello World\n===========\n'chiama la sintassi ? sostituzione variabile?
zengr,

5
@zengr: si chiama quotazione ANSI-C ed è supportato anche in zshe ksh; tuttavia, NON è conforme a POSIX.
mklement0

4
@ mkelement0, viene da ksh93, è supportato anche da zsh, bash, mksh e FreeBSD sh, e la sua inclusione nella prossima revisione principale di POSIX è in discussione
Stéphane Chazelas,

Non sembra funzionare con virgolette doppie? ad es str=$"My $PET eats:\n$PET food". Questo approccio funziona con virgolette doppie
Brad Parks il

31

È possibile inserire letteralmente nuove righe tra virgolette singole (in qualsiasi shell in stile Bourne / POSIX).

str='Hello World
===========
'

Per una stringa multilinea, qui i documenti sono spesso convenienti. La stringa viene inserita come input per un comando.

mycommand <<'EOF'
Hello World
===========
EOF

Se si desidera memorizzare la stringa in una variabile, utilizzare il catcomando in una sostituzione comando. I caratteri di nuova riga alla fine della stringa verranno rimossi dalla sostituzione del comando. Se vuoi conservare le ultime righe finali, metti un tappo alla fine e rimuovilo successivamente. Nelle shell conformi a POSIX, puoi scrivere str=$(cat <<'EOF'); str=${str%a}seguito dall'ereditarietà corretta, ma bash richiede che l'ereditarietà appaia prima della parentesi di chiusura.

str=$(cat <<'EOF'
Hello World
===========
a
EOF
); str=${str%a}

In ksh, bash e zsh, è possibile utilizzare il $'…'modulo tra virgolette per espandere le escape di barra rovesciata all'interno delle virgolette.

str=$'Hello World\n===========\n'

1
Sto usando GNU bash 4.1.5, e str=$(cat <<'EOF')non funziona così com'è. )Deve essere posizionato sulla riga successiva dopo la fine del documento EOF.. ma anche così, perde la nuova riga finale a causa di Command Sostituzione.
Peter

@fred Aspetti positivi, ho spiegato le nuove righe finali e mostrato il codice che funziona in bash. Penso che sia un bug in bash, anche se ad essere sinceri nel rileggere le specifiche POSIX trovo poco chiaro che il comportamento sia obbligatorio quando << è all'interno di una sostituzione di comando e l'eredità no.
Gilles,

Roba fantastica; per preservare le \nistanze finali (e iniziali) bashquando si acquisisce un here-doc in una variabile, considerare IFS= read -r -d '' str <<'EOF'...un'alternativa all'approccio stopper (vedere la mia risposta).
mklement0

8

Stai usando "echo"? Prova "echo -e".

echo -e "Hello World\n===========\n"

2
BTW. Non è necessario il \ n finale, perché ne echoverrà aggiunto automaticamente uno, a meno che non si specifichi -n. (Tuttavia, il peso maggiore della domanda è come inserire queste nuove righe in una variabile).
Peter

+1 Di tutte le soluzioni, questa è la più diretta e la più semplice.
Hai Vu,

echo -e non funziona in OS X
Greg M. Krsak

2
@GregKrsak: In bash, echo -e fa il lavoro su OS X - questo perché echoè un bash incorporato (piuttosto che un eseguibile esterno) e che integrato sono supportati -e. (Come un builtin, dovrebbe funzionare su tutte le piattaforme che bash gira su, tra l'altro, echo -elavora in kshe zshtroppo). Al contrario, tuttavia, l' utilità esternaecho su OS X - /bin/echo- in effetti non supporta -e.
mklement0

3

Se hai bisogno di nuove righe nella tua sceneggiatura molte volte puoi dichiarare una variabile globale che contiene una nuova riga. In questo modo puoi usarlo in stringhe tra virgolette doppie (espansioni variabili).

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"

Perché $''richiederebbe una subshell?
Mat

Mi dispiace, ho letto male una risposta.
Pihentagy,

Potrei chiedere spiegazioni ai downvoter?
Pihentagy,

Bello! Questo può essere incluso nelle variabili usando le doppie virgolette, ad es"My dog eats:${NL}dog food"
Brad Parks il

3

Da tutte le discussioni, ecco il modo più semplice per me:

bash$ str="Hello World
==========="
bash$ echo "$str"
Hello World
===========

Il comando echo deve usare virgolette doppie .


3

Per completare le grandi risposte esistenti:

Se stai usando bashe preferisci usare le nuove righe effettive per la leggibilità , readè un'altra opzione per catturare un here-doc in una variabile , che (come altre soluzioni qui) non richiede l'uso di una subshell.

# Reads a here-doc, trimming leading and trailing whitespace.
# Use `IFS= read ...` to preserve it (the trailing \n, here).
read -r -d '' str <<'EOF'   # Use `IFS= read ...` to preserve the trailing \n
Hello World
===========
EOF
# Test: output the variable enclosed in "[...]", to show the value's boundaries.
$ echo "$str"
[Hello World
===========]
  • -rassicura che readnon interpreti l'input (per impostazione predefinita, tratterebbe le barre rovesciate speciali, ma raramente è necessario).

  • -d ''imposta il delimitatore "record" su una stringa vuota, causando la readlettura dell'intero input in una sola volta (anziché una sola riga).

Si noti che lasciando $IFS(il separatore di campo interno) al suo valore predefinito, $' \t\n'(uno spazio, una scheda, una nuova riga), qualsiasi spazio bianco iniziale e finale viene tagliato dal valore assegnato a $str, che include la nuova riga finale del documento qui.
(Si noti che anche se il corpo del qui-doc inizia sulla linea dopo il delimitatore di partenza ( 'EOF'qui), esso non contiene un leader di nuova riga).

Di solito, questo è il comportamento desiderato, ma se si desidera quella nuova riga finale, utilizzare IFS= read -r -d ''invece di solo read -r -d '', ma si noti che qualsiasi spazio bianco iniziale e finale viene quindi conservato.
(Notare che anteporre IFS= direttamente al readcomando significa che l'assegnazione è attiva solo durante quel comando, quindi non è necessario ripristinare il valore precedente.)


L'uso di here-doc consente inoltre di utilizzare facoltativamente il rientro per attivare la stringa multilinea per la leggibilità:

# Caveat: indentation must be actual *tab* characters - spaces won't work.
read -r -d '' str <<-'EOF' # NOTE: Only works if the indentation uses actual tab (\t) chars.
    Hello World
    ===========
EOF
# Output the variable enclosed in "[...]", to show the value's boundaries.
# Note how the leading tabs were stripped.
$ echo "$str"
[Hello World
===========]

Posizionando -tra <<e il delimitatore qui-doc di apertura ( 'EOF', qui), i caratteri di tabulazione principali vengono rimossi dal corpo del qui-documento e persino dal delimitatore di chiusura, ma nota che questo funziona solo con caratteri di tabulazione effettivi , non spazi, quindi se il tuo editor traduce i tasti premuti nella tabulazione in spazi, è necessario un lavoro extra.


-1

devi farlo in questo modo:

STR=$(echo -ne "Hello World\n===========\n")

Aggiornare:

Come ha sottolineato Fred, in questo modo perderai il finale "\ n". Per assegnare una variabile con sequenze di barre rovesciate espanse, procedere come segue:

STR=$'Hello World\n===========\n\n'

proviamolo:

echo "[[$STR]]"

ci dà ora:

[[Hello World
===========

]]

Nota che $ '' è diverso da $ "". Il secondo esegue la traduzione in base alle impostazioni internazionali correnti. Per i dettagli vedere la sezione PREVENTIVO in man bash.


-2
#!/bin/bash

result=""

foo="FOO"
bar="BAR"

result+=$(printf '%s' "$foo")$'\n'
result+=$(printf '%s' "$bar")$'\n'

echo "$result"
printf '%s' "$result"

produzione:

FOO
BAR

FOO
BAR

1
Perché non semplicemente result+=$foo$'\n'? $(printf %s "$foo")taglierebbe i caratteri di nuova riga finali $foose presenti.
Stéphane Chazelas,

Non ci sono spiegazioni per il codice, altrimenti mi sembra perfetto.
qualcosa Qualcosa il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.