Come leggere l'input multilinea da stdin in variabile e come stamparne uno in shell (sh, bash)?

StackOverflow https://stackoverflow.com/questions/212965

  •  03-07-2019
  •  | 
  •  

Domanda

Quello che voglio fare è il seguente:

  1. leggi in più righe di input da stdin nella variabile A
  2. effettua varie operazioni su \n
  3. 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
È stato utile?

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%|||}"
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top