Come leggere l'input multilinea da stdin in variabile e come stamparne uno in shell (sh, bash)?
Domanda
Quello che voglio fare è il seguente:
- leggi in più righe di input da
stdin
nella variabileA
- effettua varie operazioni su
\n
- pipe
\r
senza perdere i simboli del delimitatore (\t
,read
,cat
, ecc.) in un altro comando
Il problema attuale è che non riesco a leggerlo con il comando <=>, perché smette di leggere a newline.
Posso leggere stdin con <=>, in questo modo:
my_var=`cat /dev/stdin`
, ma poi non so come stamparlo. In modo che la nuova riga, la scheda e altri delimitatori siano ancora lì.
Il mio script di esempio è simile al seguente:
#!/usr/local/bin/bash
A=`cat /dev/stdin`
if [ ${#A} -eq 0 ]; then
exit 0
else
cat ${A} | /usr/local/sbin/nextcommand
fi
Soluzione
Questo funziona per me:
myvar=`cat`
echo "$myvar"
Le virgolette intorno a $myvar
sono importanti.
Altri suggerimenti
In Bash, c'è un modo alternativo; man bash
menzioni:
La sostituzione del comando
$(cat file)
può essere sostituita dall'equivalente ma più veloce$(< file)
.
$ myVar=$(</dev/stdin)
hello
this is test
$ echo "$myVar"
hello
this is test
tee fa il lavoro
#!/bin/bash
myVar=$(tee)
Sì, funziona anche per me. Grazie.
myvar=`cat`
è uguale a
myvar=`cat /dev/stdin`
Beh sì. Dalla bash
pagina man:
Racchiudere i caratteri tra virgolette doppie conserva il valore letterale di tutti caratteri tra virgolette, con l'eccezione di $, `, \, e, quando l'espansione della cronologia è abilitato, !. I caratteri $ e ` mantengono il loro significato speciale tra virgolette doppie.
Se ti interessa conservare le nuove righe finali alla fine dell'output, usa questo:
myVar=$(cat; echo x)
myVar=${myVar%x}
printf %s "$myVar"
Questo utilizza il trucco di qui .
[aggiornato]
Questo incarico si bloccherà indefinitamente se non c'è nulla nella pipe ...
var="$(< /dev/stdin)"
Possiamo evitarlo facendo un timeout read
per il primo personaggio. In caso di timeout, il codice di ritorno sarà maggiore di 128 e sapremo che la pipe STDIN (a.k.a /dev/stdin
) è vuota.
Altrimenti, otteniamo il resto di STDIN entro ...
- impostando
IFS
su NULL solo per il-r
comando - disattivando le escape con
-d ''
- eliminando il delimitatore di lettura con
var="$(command ...)"
. - e infine, aggiungendolo al personaggio che inizialmente abbiamo
Quindi ...
__=""
_stdin=""
read -N1 -t1 __ && {
(( $? <= 128 )) && {
IFS= read -rd '' _stdin
_stdin="$__$_stdin"
}
}
Questa tecnica evita di usare $()
Sostituzione comandi che, in base alla progettazione, eliminerà sempre qualsiasi nuova riga finale.
Se si preferisce la sostituzione dei comandi, per preservare le nuove righe finali possiamo aggiungere uno o più caratteri delimitatori all'output all'interno di $(parens)
e quindi rimuoverli all'esterno.
Ad esempio (nota ${braces}
nel primo comando e <=> nel secondo) ...
_stdin="$(awk '{print}; END {print "|||"}' /dev/stdin)"
_stdin="${_stdin%|||}"