Dateiinhalt in Unix-Variable mit Zeilenumbrüchen

117

Ich habe eine Textdatei test.txt mit folgendem Inhalt:

text1
text2 

Und ich möchte den Inhalt der Datei einer UNIX-Variablen zuweisen, aber wenn ich das tue:

testvar=$(cat test.txt)
echo $testvar

Das Ergebnis ist:

text1 text2

anstatt

text1
text2 

Kann mir jemand eine Lösung dafür vorschlagen?

Hugo
quelle

Antworten:

184

Durch die Zuweisung werden die Zeilenumbruchzeichen nicht entfernt, sondern dies wird tatsächlich echogetan. Sie müssen einfach Anführungszeichen um die Zeichenfolge setzen, um diese Zeilenumbrüche beizubehalten:

echo "$testvar"

Dies ergibt das gewünschte Ergebnis. Eine Demo finden Sie im folgenden Transkript:

pax> cat num1.txt ; x=$(cat num1.txt)
line 1
line 2

pax> echo $x ; echo '===' ; echo "$x"
line 1 line 2
===
line 1
line 2

Der Grund, warum Zeilenumbrüche durch Leerzeichen ersetzt werden, hat nicht nur mit dem echoBefehl zu tun , sondern ist eine Kombination von Dingen.

Wenn Sie eine Befehlszeile erhalten, bashteilen Sie diese gemäß der Dokumentation für die IFSVariable in Wörter auf :

IFS: Der interne Feldtrenner, der nach der Erweiterung für die Wortteilung verwendet wird ... der Standardwert ist <space><tab><newline>.

Das bedeutet, dass standardmäßig jedes dieser drei Zeichen verwendet werden kann, um Ihren Befehl in einzelne Wörter aufzuteilen. Danach sind die Worttrennzeichen verschwunden. Sie haben nur noch eine Liste von Wörtern übrig.

Kombinieren Sie dies mit der echoDokumentation (einem bashinternen Befehl), und Sie werden sehen, warum die Leerzeichen ausgegeben werden:

echo [-neE] [arg ...]: Gibt die durch Leerzeichen getrennten Argumente aus, gefolgt von einer neuen Zeile.

Wenn Sie verwenden echo "$x", wird die gesamte xVariable gezwungen, ein einzelnes Wort zu sein bash, daher wird sie nicht aufgeteilt. Sie können das sehen mit:

pax> function count {
...>    echo $#
...> }
pax> count 1 2 3
3
pax> count a b c d
4
pax> count $x
4
pax> count "$x"
1

Hier countdruckt die Funktion einfach die Anzahl der angegebenen Argumente aus. Die 1 2 3und a b c dVarianten zeigen es in Aktion.

Dann versuchen wir es mit den beiden Variationen der xVariablen. Das eine ohne Anführungszeichen zeigt , dass es vier Worten "test", "1", "test"und "2". Das Hinzufügen der Anführungszeichen macht es zu einem einzigen Wort "test 1\ntest 2".

paxdiablo
quelle
Die Zitate ... das habe ich vermisst! Vielen Dank!
Anonymität
Auch erwähnenswert: Nachgestellte Zeilenumbrüche werden durch den Befehl Substitution Operator selbst entfernt werden: Versuchen Sie es online!
Jonah
11

Dies liegt an der IFS- Variablen (Internal Field Separator) , die Newline enthält.

$ cat xx1
1
2

$ A=`cat xx1`
$ echo $A
1 2

$ echo "|$IFS|"
|       
|

Eine Problemumgehung besteht darin, IFS vorübergehend so zurückzusetzen, dass es die neue Zeile nicht enthält :

$ IFSBAK=$IFS
$ IFS=" "
$ A=`cat xx1` # Can use $() as well
$ echo $A
1
2
$ IFS=$IFSBAK

Um diese schreckliche Veränderung für IFS rückgängig zu machen:

IFS=$IFSBAK
DVK
quelle
Ich habe diese Änderung vorgenommen, aber jetzt funktionieren meine anderen Dinge nicht. Bitte sagen Sie mir, dass ich sie zurücksetzen soll.
Pooja25
Wenn Sie es nicht benötigen, um zu einer Variablen zu wechseln, einem direkten Einzeiler:echo "$(IFS=''; cat text.txt)"
Curtis Yallop
10

In Bash -ge 4 ist die Map-Datei integriert, um Zeilen von der Standardeingabe in eine Array-Variable zu lesen.

help mapfile 

mapfile < file.txt lines
printf "%s" "${lines[@]}"

mapfile -t < file.txt lines    # strip trailing newlines
printf "%s\n" "${lines[@]}" 

Siehe auch:

http://bash-hackers.org/wiki/doku.php/commands/builtin/mapfile

todd
quelle
3

Nur wenn jemand an einer anderen Option interessiert ist:

content=( $(cat test.txt) )

a=0
while [ $a -le ${#content[@]} ]
do
        echo ${content[$a]}
        a=$[a+1]
done
DerWilts
quelle
3

Ihre Variable wird von korrekt eingestellt testvar=$(cat test.txt). Um diese Variable anzuzeigen, die aus neuen Zeilenzeichen besteht, fügen Sie einfach doppelte Anführungszeichen hinzu, z

echo "$testvar" 

Hier ist das vollständige Beispiel:

$ printf "test1\ntest2" > test.txt
$ testvar=$(<test.txt)
$ grep testvar <(set)
testvar=$'test1\ntest2'
$ echo "$testvar"
text1
text2
$ printf "%b" "$testvar"
text1
text2
Kenorb
quelle
0

Das envdirDienstprogramm bietet eine einfache Möglichkeit, dies zu tun. envdirVerwendet Dateien zur Darstellung von Umgebungsvariablen, wobei Dateinamen den Namen von env var und der Inhalt von Dateien den Werten von env var zugeordnet werden. Wenn der Dateiinhalt Zeilenumbrüche enthält, wird auch die env var.

Siehe https://pypi.python.org/pypi/envdir

Chris Johnson
quelle