Beim Lesen der Befehlsausgabe in die Variable in der Shell wird der Text an jedem Leerzeichen geteilt, nicht nur bei einer neuen Zeile.

Beim Lesen der Befehlsausgabe in die Variable in der Shell wird der Text an jedem Leerzeichen geteilt, nicht nur bei einer neuen Zeile.

Ich verwende sh (nicht bash/csh) unter FreeBSD 11 und verstehe Folgendes nicht:

In der Konsole

Befehl:zpool status -v

Ergebnis:

  pool: My_pool
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.

Zeilenweises Aufteilen und zeilenweises Drucken in einem Skript:

#!/bin/sh
zp="$(zpool status -v)"
for line in $zp; do
  echo "$line%"
done

Ergebnis:

pool:%
My_pool%
state:%
ONLINE%
status:%
One%
or%
more%
devices%
is%
currently%
being%
resilvered.%
The%
pool%
will%
continue%
to%
function,%
possibly%
in%
a%
degraded%
state.%
action:%
Wait%

Nach allem, was ich herausfinden kann, ist die von mir verwendete Syntax für sh korrekt und sollte jeweils eine Zeile und nicht jeweils ein Wort lesen.

Was vermisse ich?

Antwort1

Ich bin verwirrt über das, was Sie gefunden haben. Die von Ihnen verwendete Syntax ist für sh korrekt und teilt bei Leerzeichen, nicht nur bei Zeilenumbrüchen. Dies ist ausführlich dokumentiert. Zu denken, dass es bei Zeilenumbrüchen teilt, ist kein weit verbreiteter Irrtum. (Nicht zu verstehen, dass es teilt, ist ein weit verbreiteter Irrtum.)

Genauer gesagt wird das Weglassen einer Variablenerweiterung ohne Anführungszeichen, wie in $zp, manchmal als „Split+Glob“-Operator bezeichnet. Er bewirkt Folgendes:

  1. Übernehmen Sie den Wert der Variablen. Das ist eine Zeichenfolge.
  2. Teilen Sie diesen Wert an jedem Feldtrennzeichen auf. Ein Feldtrennzeichen ist ein Zeichen, das im Wert der Variable vorkommt IFS; standardmäßig enthält diese Variable einLeerzeichen, Tabulator und Zeilenumbruch(Dieser Standard wird auch verwendet, wenn die Variable nicht gesetzt ist.) Das Ergebnis ist eine Liste von Zeichenfolgen.
  3. Betrachten Sie jedes Element der Liste als Platzhaltermuster (Glob). Wenn es mit einem oder mehreren Dateinamen übereinstimmt, wird dieses Element durch die Liste der übereinstimmenden Dateinamen ersetzt. Andernfalls wird das Element unverändert gelassen.

Wenn das Verzeichnis beispielsweise Dateien mit den Namen foo, barund enthält baz, druckt das folgende Skript drei Zeilen: a*, barund baz.

zq='a* b*'
for word in $zq; do echo "$word"; done

Wenn Sie eine Zeichenfolge an Zeilenumbrüchen teilen möchten, können Sie dies tun, indem Sie IFSeinen Zeilenumbruch festlegen und die Platzhaltererweiterung deaktivieren.

#!/bin/sh
set -f
IFS='
'
zq=…
for line in $zq; do
done

Dies gilt für alle sh- und csh-Varianten.

Siehe auchWarum gerät mein Shell-Skript ins Stocken, wenn es sich um Leerzeichen oder andere Sonderzeichen handelt?

Antwort2

Um Zeilen zu lesen, verwenden Sie die in Ihrer Shell integriertelesenFunktion,

$Hilfe lesen | Kopf -2

lesen: lesen [-ers] [-u fd] [-t Timeout] [-p Eingabeaufforderung] [-a Array] [-n nchars] [-d delim] [Name ...]

Eine Zeile wird von der Standardeingabe gelesen, oder vom Dateideskriptor FD, wenn die Option -u angegeben ist

Setzen Sie es in eine whileSchleife ein und voilà, Sie haben die Zeilen:

$ wc -l -w ~/.profile 
  24      47 /Users/jklowden/.profile
$ for W in $(cat ~/.profile); do echo $W; done | wc -l 
  47
$ while read L; do echo $L; done < ~/.profile | wc -l 
  24

verwandte Informationen