it-swarm-tr.com

Bash içindeki bir değişkenten satır satır nasıl okuyabilirim?

Bir komutun çok satırlı çıktı içeren bir değişken var. Çıktıyı değişkenten satır satır okumanın en etkili yolu nedir?

Örneğin:

jobs="$(jobs)"
if [ "$jobs" ]; then
    # read lines from $jobs
fi
53
Eugene Yarmash

Süreç ikameli bir while döngüsü kullanabilirsiniz:

while read -r line
do
    echo "$line"
done < <(jobs)

Çok satırlı bir değişkeni okumanın en iyi yolu boş bir IFS değişkeni ve printf değişkenini bir son satırsonu ile 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: shellcheck sc2031 uyarınca, bir alt kabuk oluşturmaktan [ustaca] kaçınmak için işlem alt bölümünün kullanılması bir boruya tercih edilir.

Ayrıca, jobs değişkenini adlandırarak karışıklığa neden olabileceğini unutmayın, çünkü bu aynı zamanda ortak bir Shell komutunun adıdır.

70
dogbane

Bir komutun çıktısını satır satır işlemek için ( açıklama ):

jobs |
while IFS= read -r line; do
  process "$line"
done

Verilerinizde zaten bir değişken varsa:

printf %s "$foo" | …

printf %s "$foo", echo "$foo" İle neredeyse aynıdır, ancak $foo Kelimesini tam anlamıyla yazdırırken, echo "$foo", $foo Öğesini echo komutuna bir seçenek olarak yorumlayabilir bir - ile başlar ve bazı kabuklarda $foo içindeki ters eğik çizgi dizilerini genişletebilir.

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ı unutmayın, bu nedenle döngüde ayarladığınız herhangi bir değişken kaybedilir. Örneğin, aşağıdaki satır sayma komut dosyası bu kabuklarda 0 yazdırır:

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 döngüden $n Değerine ihtiyaç duyan parçayı) bir 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 göre hareket etmek yeterince iyi ve giriş çok büyük değilse, Word bölme özelliğini kullanabilirsiniz:

IFS='
'
set -f
for line in $(jobs); do
  # process line
done
set +f
unset IFS

Açıklama: IFS öğesinin tek bir satırsonuna ayarlanması, Word ayırmanın yalnızca satırsonlarında gerçekleşmesini sağlar (varsayılan ayarın altındaki boşluk karakterlerinin aksine). set -f, Aksi takdirde bir komut ikamesi $(jobs) veya değişken bir substitutino $foo Sonucunda meydana gelen globbing'i (yani joker karakter genişletmesi) kapatır. for döngüsü, komut çıkışındaki boş olmayan satırlar olan tüm $(jobs) parçalarına etki eder. Son olarak, globbing ve IFS ayarlarını geri yükleyin.

Sorun: while döngüsünü kullanırsanız, alt kabukta çalışır ve tüm değişkenler kaybolur. Çö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=
16
Dima
jobs="$(jobs)"
while IFS= read
do
    echo $REPLY
done <<< "$jobs"

Referanslar:

11
l0b0

Son bash sürümlerinde, komut çıkışını dizilere verimli bir şekilde okumak için mapfile veya readarray kullanın

$ readarray test < <(ls -ltrR)
$ echo ${#test[@]}
6305

Feragatname: korkunç bir örnek, ancak prolly kullanmak için kendinden daha iyi bir komut getirebilirsin

10
sehe

Yeni satırla ayrılmış verileri içeren değişkenden okumak için <<< kullanabilirsiniz:

while read -r line
do 
  echo "A line of input: $line"
done <<<"$lines"
0