`IFS = okunurken ... '' de, IFS'nin neden bir etkisi yoktur?


12

Kesinlikle yanlış bir şeyim olabilir, ancak IFS'nin önceden yapılan / yapılanlar listesindeki komutlardan biri olarak ayarlanmasının kesinlikle hiçbir etkisi olmadığına ikna edici görünüyor .
Dış IFS ( whileyapı dışında ) aşağıdaki komut dosyasında gösterilen tüm örneklerde geçerlidir.

Burada neler oluyor? IFS'nin bu durumda ne yaptığı hakkında yanlış fikrim var mı? Dizi-bölünmüş sonuçları "beklenen" sütununda gösterildiği gibi bekleniyor.


#!/bin/bash
xifs() { echo -n "$(echo -n "$IFS" | xxd -p)"; } # allow for null $IFS 
show() { x=($1) 
         echo -ne "  (${#x[@]})\t |"
         for ((j=0;j<${#x[@]};j++)); do 
           echo -n "${x[j]}|"
         done
         echo -ne "\t"
         xifs "$IFS"; echo
}
data="a  b   c"
echo -e "-----   --  -- \t --------\tactual"
echo -e "outside        \t  IFS    \tinside" 
echo -e "loop           \t Field   \tloop" 
echo -e "IFS     NR  NF \t Split   \tIFS (actual)" 
echo -e "-----   --  -- \t --------\t-----"
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while         read; do echo -ne '\t 1'; show "$REPLY"; done 
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=    read; do echo -ne '\t 2'; show "$REPLY"; done 
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=b   read; do echo -ne '\t 3'; show "$REPLY"; done
IFS=" ";      xifs "$IFS"; echo "$data" | while         read; do echo -ne '\t 4'; show "$REPLY"; done 
IFS=" ";      xifs "$IFS"; echo "$data" | while IFS=    read; do echo -ne '\t 5'; show "$REPLY"; done 
IFS=" ";      xifs "$IFS"; echo "$data" | while IFS=b   read; do echo -ne '\t 6'; show "$REPLY"; done
IFS=;         xifs "$IFS"; echo "$data" | while         read; do echo -ne '\t 7'; show "$REPLY"; done 
IFS=;         xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne '\t 8'; show "$REPLY"; done 
IFS=;         xifs "$IFS"; echo "$data" | while IFS=b   read; do echo -ne '\t 9'; show "$REPLY"; done
IFS=b;        xifs "$IFS"; echo "$data" | while IFS=    read; do echo -ne '\t10'; show "$REPLY"; done
IFS=b;        xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne '\t11'; show "$REPLY"; done
echo -e "-----   --  -- \t --------\t-----"

Çıktı:

-----   --  --   --------       actual   
outside           IFS           inside                assigned   
loop             Field          loop    #              inner
IFS     NR  NF   Split          IFS     #  expected    IFS
-----   --  --   --------       -----   #  ---------  --------
20090a   1  (3)  |a|b|c|        20090a  #                              
20090a   2  (3)  |a|b|c|        20090a  #  |a  b   c|  IFS=
20090a   3  (3)  |a|b|c|        20090a  #  |a  |   c|  IFS=b
20       4  (3)  |a|b|c|        20      #                          
20       5  (3)  |a|b|c|        20      #  |a  b   c   IFS=
20       6  (3)  |a|b|c|        20      #  |a  |   c|  IFS=b
         7  (1)  |a  b   c|             #                          
         8  (1)  |a  b   c|             #  |a|b|c|     IFS=" "
         9  (1)  |a  b   c|             #  |a  |   c|  IFS=b
62      10  (2)  |a  |   c|     62      #  |a  b   c|  IFS=
62      11  (2)  |a  |   c|     62      #  |a|b|c|     IFS=" "
-----   --  --   --------       -----      ---------   -------                        

Yanıtlar:


17

(Üzgünüm, uzun açıklama)

Evet, içindeki IFSdeğişkenin while IFS=" " read; do …kodun geri kalanında herhangi bir etkisi yoktur.

Önce kabuk komut satırının iki farklı değişken türü içerdiğini kesin olarak söyleyelim:

  • kabuk değişkenleri (yalnızca kabuk içinde bulunur ve kabuk için yereldir)
  • her süreç için var olan ortam değişkenleri. Bunlar genellikle korunur fork()ve exec()bu nedenle çocuk süreçleri onları devralır.

Aşağıdakileri içeren bir komutu çağırdığınızda:

  A=foo B=bar command

Komut (ortam) değişken bir ortam içinde yürütülür Aayarlanır foove Bayarlanır bar. Ancak bu komut satırı ile, geçerli kabuk değişkenleri Ave değişmedenB kalırlar .

Bu, aşağıdakilerden farklıdır:

A=foo; B=bar; command

Burada kabuk değişkenleri Ave Btanımlanır ve komut ortam değişkenleri olmadan çalıştırılır Ave Btanımlanır. Değerleri Ave Bbunlara erişilemiyor command.

Ancak, bazı kabuk değişkenleri export-ed ise, karşılık gelen ortam değişkenleri ilgili kabuk değişkenleriyle senkronize edilir. Misal:

export A
export B
A=foo; B=bar; command

Bu kod ile hem kabuk değişkenleri ve kabuk ortam değişkenleri ayarlanır foove bar. Ortam değişkenleri alt süreçler tarafından miras alındığı commandiçin değerlerine erişebilecektir.

Orijinal sorunuza geri dönmek için:

IFS='a' read

sadece readetkilenir. Ve aslında, bu durumda, değişkenin readdeğerini umursamıyor IFS. O kullanır IFSsen gibi, bölünmüş (ve çeşitli değişkenlere saklanır) olmak hattını sorduğunuzda sadece:

echo "a :  b :    c" | IFS=":" read i j k; \
    printf "i is '%s', j is '%s', k is '%s'" "$i" "$j" "$k"

IFSreadargümanlarla çağrılmadığı sürece tarafından kullanılmaz . ( Düzenle: Bu tam olarak doğru değildir: boşluk ve sekme gibi boşluk karakterleri IFSgiriş satırının başında / sonunda her zaman yok sayılır.)


Ne harika bir açıklama! Çok basit! Aylardır ' noktalı virgül yok' sözdiziminden şaşkına döndüm ; ve bu sadece yerel bir değişken anlamına gelen bir durum! .. rozcietrzewiacz benim için yolu açtı (büyük zaman) diğer soru ... ve sadece kek üzerine krema koymak ... Bütün gece bu bir ve kesinlikle böyle iyi ve net cevaplar için buna değer oldu! .. Teşekkür ederim ..
Peter.O

Uhm. Bu düzenleme yorumunu almadan önce birkaç kez okumak zorunda kaldım - mevcut beyaz karakterlerin $IFSgiriş satırının başında / sonunda kaldırıldığını söylemek mi istiyorsunuz ? (Bu nasıl çalışır.)
zrajm


IFS değeri olan kabuk hala girişi kelime bölme yapar, çünkü tek bir değişken okuma bile önemli. Örneğin, karakterleri a<tab>biçine yazmak read varvar değerine sahip olur a<space>b, ancak bunun yerine IFS='<newline>' read varvar değerine sahip olur a<tab>b.
John Hascall

8

Basit koy, bir defada birden fazla değişkene okumalıdır için IFS=<something> read ...yapı sizin örneklerde görünür bir etkiye sahip 1 .

readÖrneklerin kapsamını kaçırdınız. Orada hiçbir test durumlarda döngü içine IFS modifikasyonu. Tam olarak işaret etmeme izin verin, ikinci IFS'nin satırlarınızın her birinde etkisi nedir:

 IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=b   read; do echo ...
                                                      ^      ^
                                                      |      |
                                          from here --'       `- to here :)

Kabukta yürütülen herhangi bir programda olduğu gibi. Komut satırında tanımladığınız değişken, programın yürütülmesini etkiler. Ve sadece bu (ihracat yapmadığınız için). Bu nedenle, IFSbu satırda yeniden tanımlanmış bir özellik kullanmak readiçin birden fazla değişkene değer atamanız gerekir . Aşağıdaki örneklere bir göz atın:

 $ data="a  b   c"
 $ echo "$data" | while           read A B C; do echo \|$A\|$B\|\|$C\|; done
 |a|b||c|
 $ echo "$data" | while IFS=      read A B C; do echo \|$A\|$B\|\|$C\|; done
 |a b c||||
 $ echo "$data" | while IFS='a'   read A B C; do echo \|$A\|$B\|\|$C\|; done
 || b c|||
 $ echo "$data" | while IFS='ab'  read A B C; do echo \|$A\|$B\|\|$C\|; done
 || || c|

1 Gilles'ten öğrendiğim gibi , aslında IFS=''sadece bir alanı okurken (boş) ayarlamanın bir yararı olabilir : satırın başındaki boşlukların kesilmesini önler.


İyi .. Teşekkürler ... Bu sefer anladım .. ve eskizini seviyorum :)
Peter.O

Tamam, şimdi diğer soruda bu konudaki cevabımı fark etmediğini gören yorumunu okudum. Belki de diğerini geri alıp silebilirsiniz, çünkü bu gerçekten genel bir konudur?
rozcietrzewiacz

Evet, iki sorunun ilişkili bir teması vardır, ancak diğerinin başlığı "Neden IFS= readsadece IFS ortam değişkenini yeniden ayarlamak için kullanılır " dır . O halde yerel değişkenlerin bir emir arayan tarafından belirlenebileceğine dair farkındalığım yoktu. Bu sorunun cevabı buydu. Bu sorunun ana konusunu ele almak için daha da gelişti, ancak farkına vardığım zaman, bu soruyu zaten sormuştum ... Belki de iki soru iki soruya benzer sed, bu yüzden asis'i tutmayı hissediyorum ... Google'a giden Google kullanıcıları için daha fazla başlık .
Peter.O
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.