Bir komutun çok satırlı çıktısını içeren bir değişken var. Çıkış satırını değişkenden satır satır okumanın en etkili yolu nedir?
Örneğin:
jobs="$(jobs)"
if [ "$jobs" ]; then
# read lines from $jobs
fi
Bir komutun çok satırlı çıktısını içeren bir değişken var. Çıkış satırını değişkenden satır satır okumanın en etkili yolu nedir?
Örneğin:
jobs="$(jobs)"
if [ "$jobs" ]; then
# read lines from $jobs
fi
Yanıtlar:
Bir süre döngü işlem değiştirme ile kullanabilirsiniz:
while read -r line
do
echo "$line"
done < <(jobs)
Çok satırlı bir değişkeni okumanın en iyi yolu, boş bir IFSdeğişkeni ve printfdeğişkeni izleyen bir satırsonu ayarlamaktır:
# Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
# variable that doesn't end with a newline then the while loop will
# completely miss the last line of the variable.
while IFS= read -r line
do
echo "$line"
done < <(printf '%s\n' "$var")
Not: kabuk kontrolü sc2031'e göre , bir alt kabuk oluşturmaktan [ince bir şekilde] kaçınmak için işlem alt bölümünün kullanılması bir boruya tercih edilir.
Ayrıca, değişkeni isimlendirmenin jobskarışıklığa yol açabileceğini lütfen unutmayın, çünkü bu aynı zamanda ortak bir kabuk komutunun adıdır.
echoiçin printf %sbetiğinize olmayan uysal girişli bile çalışacak böylece.
/tmp, geçici bir çalışma dosyası oluşturabilmeye dayandığından, her zaman dizinin yazılabilir olmasını gerektirdiği belirtilmelidir . Kısıtlı bir sistemde /tmpsalt okunur olma (ve sizin tarafınızdan değiştirilemeyen) durumunuzu bulursanız, alternatif bir çözüm, örneğin printfboru ile kullanma olasılığından memnun olacaksınız .
printf "%s\n" "$var" | while IFS= read -r line
Bir komut satırının çıktısını satır satır işlemek için ( açıklama ):
jobs |
while IFS= read -r line; do
process "$line"
done
Verileri zaten bir değişkende varsa:
printf %s "$foo" | …
printf %s "$foo"hemen hemen aynıdır echo "$foo", fakat baskılar $fooise tam anlamıyla echo "$foo"yorumlayabilir $foobir başlıyorsa yankı komutuna bir seçenek olarak -ve de ters eğik çizgi dizileri genişleyebilir $foobazı kabuklarda.
Bazı kabuklarda (kül, bash, pdksh, ancak ksh veya zsh değil), bir boru hattının sağ tarafının ayrı bir işlemde çalıştığını ve döngüde ayarladığınız herhangi bir değişkenin kaybolduğunu unutmayın. Örneğin, aşağıdaki satır sayma komut dosyası bu kabuklarda 0 basar:
n=0
printf %s "$foo" |
while IFS= read -r line; do
n=$(($n + 1))
done
echo $n
Çözüm, komut dosyasının geri kalanını (veya en azından $ndöngünün değerini gerektiren kısmı ) komut listesine koymaktır :
n=0
printf %s "$foo" | {
while IFS= read -r line; do
n=$(($n + 1))
done
echo $n
}
Boş olmayan satırlara etki etmek yeterince iyi ise ve girdi çok büyük değilse, bölme kelimesini kullanabilirsiniz:
IFS='
'
set -f
for line in $(jobs); do
# process line
done
set +f
unset IFS
Açıklama: IFStek bir yeni satıra ayarlamak , kelime bölmenin yalnızca yeni satırlarda yapılmasını sağlar (varsayılan ayardaki herhangi bir boşluk karakterinin aksine). set -fKomut ikame edilmesi $(jobs)veya değişken ikame edici sonucu ortaya çıkacak olan globbing'i (yani joker karakter genişlemesi) kapatır $foo. forDöngüsü, tüm ilgili parçalarını hareket $(jobs)komutu çıkışı boş olmayan tüm satırları,. Son olarak, genelleme ve IFSayarları geri yükleyin .
local IFS=something. Global kapsam değerini etkilemez. IIRC, unset IFSsizi varsayılana döndürmez (önceden varsayılan değilse kesinlikle çalışmaz).
Sorun: Eğer döngü kullanırken kullanırsanız alt kabukta çalışacak ve tüm değişkenler kaybolacak. Çözüm: döngü için kullanın
# change delimiter (IFS) to new line.
IFS_BAK=$IFS
IFS=$'\n'
for line in $variableWithSeveralLines; do
echo "$line"
# return IFS back if you need to split new line by spaces:
IFS=$IFS_BAK
IFS_BAK=
lineConvertedToArraySplittedBySpaces=( $line )
echo "{lineConvertedToArraySplittedBySpaces[0]}"
# return IFS back to newline for "for" loop
IFS_BAK=$IFS
IFS=$'\n'
done
# return delimiter to previous value
IFS=$IFS_BAK
IFS_BAK=
while readbash içindeki bir döngüye borulamak , while döngüsünün bir alt kabukta olduğu anlamına gelir, bu nedenle değişkenler global değildir. while read;do ;done <<< "$var"döngü gövdesini alt kabuk değil yapar. (Son bash, cmd | whileksh'nin her zaman olduğu gibi, bir alt gövdesinin alt gövdesinde olmayan bir döngünün gövdesini koyma seçeneğine sahiptir.)
Son bash sürümlerinde, komut çıktısını dizilere verimli bir şekilde okumak için kullanın mapfileveya readarraykullanın
$ readarray test < <(ls -ltrR)
$ echo ${#test[@]}
6305
Feragatname: korkunç bir örnek, ancak kendinizden daha iyi bir komutla gelebilirsiniz.
readarraybir fonksiyon koyun ve fonksiyonu birkaç kez çağırın.
jobs="$(jobs)"
while IFS= read
do
echo $REPLY
done <<< "$jobs"
Referanslar:
-rbu da iyi bir fikirdir; \` interpretation... (it is in your links, but its probably worth mentioning, just to round out your IFS = `yi engeller (boşluk kaybını önlemek için esastır)
Yeni satırla ayrılmış verileri içeren değişkenden okumak için <<< öğesini kullanabilirsiniz:
while read -r line
do
echo "A line of input: $line"
done <<<"$lines"
while IFS= read... \ yorumlamayı önlemek istiyorsanız, o zaman kullanınread -r