Come posso leggere più righe da STDIN in una variabile?


24

Ho cercato su Google questa domanda senza alcun risultato. Sto automatizzando un processo di compilazione qui al lavoro e tutto ciò che sto cercando di fare è ottenere i numeri di versione e una piccola descrizione della compilazione che può essere multi-riga. Il sistema su cui gira è OSX 10.6.8.

Ho visto di tutto, dall'uso di CAT all'elaborazione di ogni riga, se necessario. Non riesco a capire cosa dovrei usare e perché.

tentativi

read -d '' versionNotes

Risultati immessi confusi se l'utente deve utilizzare il tasto backspace. Inoltre, non esiste un buon modo per terminare l'input poiché ^ D non termina e ^ C esce semplicemente dal processo.

read -d 'END' versionNotes

Funziona ... ma altera ancora l'input se è necessaria la chiave backspace.

while read versionNotes
do
  echo "  $versionNotes" >> "source/application.yml"
done

Non termina correttamente l'input (perché sono troppo tardi per cercare la corrispondenza con una stringa vuota).


Ricevi queste informazioni dall'utente, giusto?
Glenn Jackman,

Corretta; Voglio che l'utente inserisca queste informazioni nel terminale quando esegue lo script.
Robert K,

1
Non ti sei chiarito, preferirei dire.
poige,

Risposte:


20

man bash menziona «...

La sostituzione del comando $ (file cat) può essere sostituita da $ (<file) equivalente ma più veloce.

... »

$ myVar=$(</dev/stdin)
hello
this is test
$ echo $myVar
hello this is test
$ echo "$myVar"
hello
this is test

e sono d'accordo che vale la pena menzionare - echo "$myVar"avrebbe mostrato l'input come è stato dato.


1
Come fermarsi dopo l'input multilinea? Se premo Ctrl C si ferma ma la variabile non viene salvata!
Nikhil,

2
I terminali UNIX hanno "disciplina": en.wikipedia.org/wiki/Line_discipline • Scopri cosa significa "eof" • Leggi man stty, scopri come ottenere le impostazioni correnti
poige

2
ctrl-d per interrompere.
freb

9

Prova questo:

user@host:~$ read -d '' x <<EOF
> mic
> check
> one
> two
> EOF

Senza interruzioni di riga:

user@host:~$ echo $x
mic check one two

Con interruzioni di riga:

user@host:~$ echo "$x"
mic
check
one
two

2
-d ''è esattamente quello di cui avevo bisogno. Grazie
Bruno Bronosky

@Bruno Il mio piacere; è difficile. Soprattutto a prima vista, sembra abbastanza standard. Può essere abbastanza utile, una volta che hai capito le varie idiosincrasie.
esprime l'


2

Ho risolto questo problema trattando ogni riga fino a quando non ho trovato una riga vuota. Funziona abbastanza bene per la mia situazione. Ma se qualcuno vuole aggiungere una soluzione migliore, sentiti libero di farlo.

echo "---
notes: |" > 'version.yml'

while read line
do
  # break if the line is empty
  [ -z "$line" ] && break
  echo "  $line" >> "source/application.yml"
done

Usa read -rinvece.
adattamento

2

Puoi avviare un editor come vim, pico ...

${VISUAL:-${EDITOR:-vi}} source/application.yml

Um ... come risponde alla domanda del PO in qualche modo?
adattamento

Può avviare l'editor dallo script.
Mircea Vutcovici,

E questo realizza esattamente cosa? Vuole usare il testo di un file nello script, non scrivere informazioni in un file.
adattamento

Non è in grado di leggere il testo dall'utente e di scriverlo in un file. Si prega di leggere i commenti aggiunti alla domanda.
Mircea Vutcovici,

1

Prima alcune correzioni:

  1. Per consentire la "versione" sulla linea, utilizzare -eche utilizza readline (in modo da avere la cronologia bash e tutte le funzionalità di modifica)
  2. -dprende solo un personaggio. Ad esempio da 'END' prende 'E' e ogni volta che l'utente scrive una 'E' la lettura si interrompe (suppongo che non sia quello che vuoi ...)

Ci sono alcune possibilità per farlo. Vorrei leggere riga per riga e interrompere quando viene trovata una riga vuota (anche se è possibile impostare qualsiasi parola di arresto):

unset tmp
while :
do 
 read line
 [[ $line == "" ]] && tmp="${tmp:0:$((${#tmp}-1))}" && break
 tmp="$tmp"$line$'\n'
done

0

Hai diversi metodi.

Uno dei metodi più semplici è:

MYVAR=$(yourcommand)
echo $"MYVAR"

Per esempio:

MYVAR=$(ls /)
echo $"MYVAR"

Solo che non sto eseguendo un comando shell come LS. Sto richiedendo un input multilinea da parte dell'utente.
Robert K,

Questa è una pessima pratica; non elaborare l'output di ls!
adattamento

@adaptr Abbiamo già sentito tutto prima, ti dispiacerebbe suggerire una buona alternativa, per favore?
esprime l'

0

Stiamo usando un costrutto usando xargs e ctrl-d per rompere. Non ne sono perfettamente soddisfatto, ma certamente fa il lavoro di prendere l'input dell'utente multilinea e inserirlo in una variabile (formattazione intatta). (Il primo e il terzo compito aggiungono virgolette attorno al contenuto dell'input xargs.)

    printf "\\033[1mWhen finished hit ctrl-d on a new line to proceed.\\033[0m  \\n\\n" 
    # this will load the user's input into a variable instead of a file 
    reminderBody="\"" 
    reminderBody+=$( xargs -0 ) 
    reminderBody+="\"" 

Usiamo reminderBody come oggetto di una e-mail inviata per posta (via bash).


-1

Vedi: http://tldp.org/LDP/abs/html/internal.html#READR

Utilizzare reade notare che se si termina una riga con \la nuova riga viene ignorata. Quindi potresti fare:

#! / Bin / bash

leggi -p "versione:" versione
echo $ version

# inserisci alcuni input e termina le righe lunghe con "\", quindi inserisci semplicemente alla fine
leggi -p "descrizione:" descrizione
echo -e "$ versione \ n $ descrizione >> yourfile.txt

Se volevo solo ignorare un paragrafo con le interruzioni di riga, sì. Ma poiché questo è un elenco generato di note di rilascio per uno script di build, devo essere in grado di preservare quelle interruzioni di riga; Potrei provare ad inserire un elenco puntato, ad esempio.
Robert K,

L'ABS è una mostruosità di proporzioni orribili. Il 90% è chiaramente sbagliato.
adattamento

Non è poi così male.
esprime l'
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.