Wie lese ich mehrere Zeilen von STDIN in eine Variable?


24

Ich habe diese Frage vergeblich gegoogelt. Ich automatisiere hier bei der Arbeit einen Build-Prozess, und alles, was ich versuche, ist, Versionsnummern und eine winzige Beschreibung des Builds abzurufen, die möglicherweise mehrzeilig sein kann. Das System, auf dem dies ausgeführt wird, ist OSX 10.6.8.

Ich habe alles von der Verwendung von CAT bis zur Verarbeitung jeder Zeile nach Bedarf gesehen. Ich kann nicht herausfinden, was ich verwenden soll und warum.

Versuche

read -d '' versionNotes

Dies führt zu unleserlichen Eingaben, wenn der Benutzer die Rücktaste verwenden muss. Es gibt auch keine gute Möglichkeit, die Eingabe zu beenden, da ^ D nicht beendet wird und ^ C nur den Prozess beendet.

read -d 'END' versionNotes

Funktioniert ... verstümmelt aber die Eingabe, wenn die Rücktaste benötigt wird.

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

Beendet die Eingabe nicht ordnungsgemäß (da ich zu spät bin, um nach einer leeren Zeichenfolge zu suchen).


Sie erhalten diese Informationen vom Benutzer, richtig?
Glenn Jackman

Richtig; Ich möchte, dass der Benutzer diese Informationen beim Ausführen des Skripts in das Terminal eingibt.
Robert K

1
Du hast dich nicht klar ausgedrückt, würde ich eher sagen.
Poige

Antworten:


20

man bash Erwähnungen «…

Die Befehlsersetzung $ (cat-Datei) kann durch die entsprechende, aber schnellere $ (<Datei) ersetzt werden.

… »

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

und ich stimme zu, dass dies erwähnenswert ist - echo "$myVar"hätte die Eingabe so angezeigt, wie sie gegeben wurde.


1
Wie stoppe ich nach mehrzeiliger Eingabe? Wenn ich Strg + C drücke, stoppt es, aber die Variable wird nicht gespeichert!
Nikhil

2
UNIX®-Terminals haben "Disziplin": en.wikipedia.org/wiki/Line_discipline • Überprüfen Sie, was "eof" bedeutet. • Lesen man sttySie, wie Sie die aktuellen Einstellungen
abrufen

2
ctrl-d um anzuhalten.
Freb

9

Versuche dies:

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

Ohne Zeilenumbrüche:

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

Mit Zeilenumbrüchen:

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

2
-d ''ist genau das, was ich brauchte. Vielen Dank
Bruno Bronosky

@Bruno Mein Vergnügen; Es ist eine knifflige Sache. Besonders auf den ersten Blick sieht es ziemlich normal aus. Kann jedoch sehr nützlich sein, wenn Sie die verschiedenen Besonderheiten verstanden haben.
Stimmen


2

Ich habe dieses Problem gelöst, indem ich mich mit jeder Zeile befasst habe, bis ich eine leere Zeile gefunden habe. Es funktioniert gut genug für meine Situation. Wenn Sie jedoch eine bessere Lösung hinzufügen möchten, können Sie dies tun.

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

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

Verwenden Sie read -rstattdessen.
25.

2

Sie können einen Editor wie vim, pico ... starten

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

Ähm ... wie beantwortet das die Frage des OP in irgendeiner Weise?
25.

Er kann den Editor aus dem Skript heraus starten.
Mircea Vutcovici

Und was genau leistet das? Er möchte Text aus einer Datei im Skript verwenden und keine Informationen in eine Datei schreiben .
25.

Er wollte keinen Text vom Benutzer lesen und in eine Datei schreiben. Bitte lesen Sie die der Frage hinzugefügten Kommentare.
Mircea Vutcovici

1

Zuerst ein paar Korrekturen:

  1. Um "edition" in der Zeile zuzulassen -e, verwenden Sie readline (damit Sie den Bash-Verlauf und alle Bearbeitungsfunktionen haben).
  2. -dNimmt nur ein Zeichen. ZB 'END' nimmt 'E' und wenn der Benutzer ein 'E' schreibt, stoppt der Lesevorgang (ich denke, das ist nicht das, was Sie wollen ...)

Hierfür gibt es einige Möglichkeiten. Ich würde Zeile für Zeile lesen und anhalten, wenn eine leere Zeile gefunden wird (obwohl Sie ein beliebiges Stoppwort setzen könnten):

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

0

Sie haben mehrere Methoden.

Eine der einfachsten Methoden ist:

MYVAR=$(yourcommand)
echo $"MYVAR"

Beispielsweise:

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

Es sei denn, ich führe keinen Shell-Befehl wie LS aus. Ich fordere vom Benutzer eine mehrzeilige Eingabe an.
Robert K

Dies ist eine sehr schlechte Praxis. Verarbeiten Sie nicht die Ausgabe von ls!
25.

@adaptr Wir haben schon alles gehört. Würde es Ihnen etwas ausmachen, eine gute Alternative vorzuschlagen?
Stimmen

0

Wir verwenden ein Konstrukt mit xargs und ctrl-d zum Brechen. Ich bin nicht vollkommen zufrieden damit, aber es erledigt mit Sicherheit die Aufgabe, mehrzeilige Benutzereingaben zu übernehmen und diese in eine Variable einzufügen (Formatierung intakt). (Bei der ersten und dritten Zuweisung werden die Inhalte der xargs-Eingabe in Anführungszeichen gesetzt.)

    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+="\"" 

Wir verwenden reminderBody als Betreff einer E-Mail, die per Post verschickt wird (via Bash).


-1

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

Verwenden Sie readund beachten Sie, dass, wenn Sie eine Zeile mit \dem Zeilenumbruch beenden, ignoriert wird. Sie könnten also Folgendes tun:

#! / bin / bash

read -p "version:" version
echo $ version

# Geben Sie einige Eingaben ein und beenden Sie lange Zeilen mit "\", und geben Sie sie am Ende einfach ein
read -p "description:" Beschreibung
echo -e "$ version \ n $ description >> yourfile.txt

Wenn ich nur wollte, dass ein Absatz mit Zeilenumbrüchen ignoriert wird, ja. Da dies jedoch eine generierte Liste von Versionshinweisen für ein Build-Skript ist, muss ich in der Lage sein, diese Zeilenumbrüche beizubehalten. Ich könnte beispielsweise versuchen, eine Liste mit Aufzählungszeichen einzugeben.
Robert K

Das ABS ist eine Monstrosität von schrecklichen Ausmaßen. 90% davon sind einfach falsch.
25.

Es ist nicht so schlimm.
Stimmen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.