Nuova riga in variabili bash


9

Sto cercando di memorizzare più righe in una variabile bash, ma non sembra funzionare.

Ad esempio, se elenco /binun file per riga e lo memorizzo $LS, quindi passo $LScome stdin a wc, restituisce sempre 1:

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

Se provo a stampare sullo schermo, ottengo vari risultati: echostampa tutte le linee su una sola linea, mentre printfstampa solo la prima riga:

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

Quindi, una variabile bash può contenere più righe?

Risposte:


15

Devi raddoppiarlo tra virgolette (e nella maggior parte dei casi dovresti raddoppiare le variabili ):

echo "$LS"

Ma non usare echo per stampare il contenuto delle variabili, usando invece printf :

printf '%s\n' "$LS"

1
Giusto per dare un punto più fine alla risposta generale: printf si aspetta che una stringa di formato sia il suo primo parametro, motivo per cui non hanno visto ciò che si aspettavano. Se vogliono vedere nuove righe nell'output di printf, divise arbitrariamente su spazi, printf "%s\n" $LSlo farebbero.
Jeff Schaller

% LS dovrebbe essere $ LS, a proposito (non potrei fare una modifica così breve)
Jeff Schaller

Grazie! Naturalmente funziona anche con wce altri comandi:wc -l <<< "$LS"
Wizard79,

1
@JeffSchaller: No, in questo caso non dovresti annullare la quotazione della variabile, usando solo printf '%s\n' "$LS"se vuoi vedere newline. È un errore di battitura, risolto!
cuonglm,

Perché non dovresti usare l'eco per stampare le variabili?
123,

9

Le nuove righe sono nella variabile. LS=$(ls -1)imposta la variabile LSsull'output di ls -1(che produce lo stesso output di ls, a proposito, tranne quando l'output arriva a un terminale), meno le nuove righe finali.

Il problema è che stai rimuovendo le nuove righe quando stampi il valore. In uno script shell, $LSnon significa "il valore della variabile LS", significa "prendere il valore di LS, dividerlo in parole secondo IFSe interpretare ogni parola come un modello glob". Per ottenere il valore di LS, è necessario scrivere "$LS", o più in generale, $LStra virgolette doppie.

echo "$LS"stampa il valore di LS, tranne in alcune shell che interpretano i caratteri di barra rovesciata e ad eccezione di alcuni valori che iniziano con -.

printf "$LS"stampa il valore LSpurché non contenga alcun carattere percentuale o barra rovesciata e (con la maggior parte delle implementazioni) non inizi con -.

Per stampare LSesattamente il valore , utilizzare printf %s "$LS". Se vuoi una nuova riga alla fine, usa printf '%s\n' "$LS".

Si noti che $(ls)non è, in generale, l'elenco dei file nella directory corrente. Funziona solo quando hai abbastanza nomi di file da domare. Per ottenere l'elenco dei nomi dei file (eccetto i file dot), è necessario utilizzare un carattere jolly: *. Il risultato è un elenco di stringhe, non una stringa, quindi non è possibile assegnarlo a una variabile stringa; puoi usare una variabile array files=(*)nelle shell che le supportano (ksh93, bash, zsh).

Per ulteriori informazioni, vedi Perché il mio script shell si soffoca su spazi bianchi o altri caratteri speciali?


printf "$ LS" soccomberebbe anche al backslash dell'analisi dei personaggi, simile all'eco
cnst

0

Il suddetto

printf '%s\n' "$LS"

è l'unica soluzione corretta.

Consentitemi di dimostrare che le altre soluzioni proposte, sia con echoche printfsemplicemente, non funzionano correttamente:

$ 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
$

(Si può anche testare con V=$(printf 'line0:\\n\\n\nline1.\n') printf '%s\n' "$V"e variazioni.)

Mentre \nnei nomi dei file potrebbe non essere così comune, archiviarli git diffin una variabile e le tue possibilità di incontrare letteralmente \naumentano in modo drammatico.


Si noti che kshe zshanche il supporto print -r -- "$LS"e zshanche ha echo -E - $LS. cshha echo $LS:qperò che non genera il carattere di nuova riga se $ LS è vuoto, e ottenere un valore multilinea in $ LS in primo luogo è piuttosto complicato in csh.
Stéphane Chazelas,
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.