S1. Alan bölme.
Alan bölme, sözcük bölme ile aynı mıdır?
Evet, ikisi de aynı fikri işaret ediyor.
Ayar IFS=''
null ile aynı, boş bir dize ile aynı mı?
Evet, her üçü de aynı anlama geliyor: Hiçbir alan / kelime bölme işlemi gerçekleştirilmeyecek. Ayrıca, bu baskı alanlarını etkiler (olduğu gibi echo "$*"
) tüm alanlar boşluksuz olarak birleştirilir.
S3: (bölüm a) IFS'yi ayarlayın.
POSIX şartnamesinde aşağıdakileri okudum :
Eğer IFS ayarlanmamışsa, kabuk, IFS değeri <boşluk ><tab> <yeni satır> gibi davranır .
Hangi tam olarak eşdeğerdir:
Bir ile unset IFS
kabuk, IFS varsayılanmış gibi davranır.
Bu, 'Alan bölmesinin' varsayılan bir IFS değeriyle tam olarak aynı olacağı veya ayarlanamayacağı anlamına gelir.
Bu, IFS'nin her koşulda aynı şekilde çalışacağı anlamına gelmez. Daha spesifik olmak gerekirse, çalıştırma, varsayıyı varsayılan değer yerine nullOldIFS=$IFS
değerine ayarlar . Ve IFS’yi geri almaya çalışmak, bunun gibi, IFS’yi null olarak ayarlayacaktır, eskisi gibi rahatsız etmemek için. Dikkat et !!.OldIFS
IFS=OldIFS
S3: (bölüm b) IFS'yi geri yükleyin.
IFS değerini varsayılan ayarlara nasıl geri getirebilirim. Varsayılan IFS değerini geri yüklemek istediğimi söyleyin. Bunu nasıl yaparım? (daha spesifik olarak, <tab> ve <newline> ' ı nasıl ifade edebilirim ?)
Zsh, ksh ve bash (AFAIK) için, IFS aşağıdaki gibi varsayılan değere ayarlanabilir:
IFS=$' \t\n' # works with zsh, ksh, bash.
Tamam, başka bir şey okumalısın.
Ancak IFS'yi sh için yeniden ayarlamanız gerekirse, karmaşık olabilir.
En kolay şekilde tamamlayacağımız bir dezavantaj olmadan (karmaşıklık hariç) bir göz atalım.
1.-IFS'yi ayarlayın.
Biz sadece unset IFS
(Yukarıdaki Q3 bölüm a.) Okuyun.
2.- Karakter değişimi.
Geçici bir çözüm olarak, tab ve newline değerlerinin değiştirilmesi, IFS değerini ayarlamayı kolaylaştırır ve ardından eşdeğer bir şekilde çalışır.
IFS'yi <boşluk ><newline> <tab> olarak ayarlayın :
sh -c 'IFS=$(echo " \n\t"); printf "%s" "$IFS"|xxd' # Works.
3.- Basit mi? çözüm:
IFS'nin doğru ayarlanması gereken alt komut dosyaları varsa, her zaman manuel olarak yazabilirsiniz:
IFS ='
'
Elle yazılan dizinin olduğu yer:, IFS=
'spacetabnewline'yukarıda doğru şekilde yazılan dizinin sırasıdır (Onaylamanız gerekiyorsa, bu yanıtı düzenleyin). Ancak tarayıcınızın kopyala / yapıştır özelliği kırılır, çünkü tarayıcı boşlukları sıkar / gizler. Kodu yukarıda yazılı şekilde paylaşmayı zorlaştırır.
4.- Komple çözüm.
Güvenli bir şekilde kopyalanabilen kodlar yazmak, genellikle kesin olarak basılabilen çıkışlardan ibarettir.
Beklenen değeri "üreten" bir koda ihtiyacımız var. Ancak, kavramsal olarak doğru olsa bile, bu kod bir iz bırakmaz \n
:
sh -c 'IFS=$(echo " \t\n"); printf "%s" "$IFS"|xxd' # wrong.
Bu, çoğu kabuk altında , genişleyen tüm yeni satırları $(...)
veya `...`
komut değiştirmeleri kaldırıldığı için olur.
Sh için bir numara kullanmalıyız :
sh -c 'IFS="$(printf " \t\nx")"; IFS="${IFS%x}"; printf "$IFS"|xxd' # Correct.
Alternatif bir yol, IFS'yi bash'tan bir ortam değeri olarak ayarlamak (örneğin) ve sonra sh (IFS'yi çevre yoluyla ayarlanmasını kabul eden versiyonları) olarak ayarlamak olabilir:
env IFS=$' \t\n' sh -c 'printf "%s" "$IFS"|xxd'
Kısacası, sh, IFS'yi varsayılan olarak oldukça garip bir maceraya sıfırlamayı sağlıyor.
S4: Gerçek kodda:
Son olarak, bu kod nasıl olurdu:
while IFS= read -r line
do
echo $line
done < /path_to_text_file
ilk satırı değiştirdiğimizde davran
while read -r line # Use the default IFS value
veya:
while IFS=' ' read -r line
İlk olarak: echo $line
(alıntı DEĞİLDİR) ile porpouse olup olmadığını bilmiyorum. Okunmamış olan ikinci bir 'alan bölme' seviyesini tanıtır. Yani ikisine de cevap vereceğim. :)
Bu kodla (böylece onaylayabilirsiniz). Kullanışlı xxd'ye ihtiyacınız olacak :
#!/bin/ksh
# Correctly set IFS as described above.
defIFS="$(printf " \t\nx")"; defIFS="${defIFS%x}";
IFS="$defIFS"
printf "IFS value: "
printf "%s" "$IFS"| xxd -p
a=' bar baz quz '; l="${#a}"
printf "var value : %${l}s-" "$a" ; printf "%s\n" "$a" | xxd -p
printf "%s\n" "$a" | while IFS='x' read -r line; do
printf "IFS --x-- : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf 'Values quoted :\n' "" # With values quoted:
printf "%s\n" "$a" | while IFS='' read -r line; do
printf "IFS null quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf "%s\n" "$a" | while IFS="$defIFS" read -r line; do
printf "IFS default quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
unset IFS; printf "%s\n" "$a" | while read -r line; do
printf "IFS unset quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
IFS="$defIFS" # set IFS back to default.
printf "%s\n" "$a" | while IFS=' ' read -r line; do
printf "IFS space quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf '%s\n' "Values unquoted :" # Now with values unquoted:
printf "%s\n" "$a" | while IFS='x' read -r line; do
printf "IFS --x-- unquoted : "
printf "%s, " $line; printf "%s," $line |xxd -p; done
printf "%s\n" "$a" | while IFS='' read -r line; do
printf "IFS null unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
printf "%s\n" "$a" | while IFS="$defIFS" read -r line; do
printf "IFS defau unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
unset IFS; printf "%s\n" "$a" | while read -r line; do
printf "IFS unset unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
IFS="$defIFS" # set IFS back to default.
printf "%s\n" "$a" | while IFS=' ' read -r line; do
printf "IFS space unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
Alırım:
$ ./stackexchange-Understanding-IFS.sh
IFS value: 20090a
var value : bar baz quz -20202062617220202062617a20202071757a2020200a
IFS --x-- : bar baz quz -20202062617220202062617a20202071757a202020
Values quoted :
IFS null quoted : bar baz quz -20202062617220202062617a20202071757a202020
IFS default quoted : bar baz quz-62617220202062617a20202071757a
IFS unset quoted : bar baz quz-62617220202062617a20202071757a
IFS space quoted : bar baz quz-62617220202062617a20202071757a
Values unquoted :
IFS --x-- unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS null unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS defau unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS unset unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS space unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
İlk değer sadece doğru değerdir IFS=
'spacetabnewline'
Sonraki satır, var değerinin tüm altıgen değerleri $a
ve sonunda her okuma komutuna verilecek olan yeni bir '0a' satırıdır.
IFS'nin boş olduğu bir sonraki satır, herhangi bir 'alan ayırma' gerçekleştirmez, ancak yeni satır kaldırılır (beklendiği gibi).
Sonraki üç satır, IFS bir boşluk içerdiğinden, ilk boşlukları kaldırın ve var çizgisini kalan bakiyeye ayarlayın.
Son dört satır, alıntılanmamış bir değişkenin ne yapacağını gösterir. Değerler (birkaç) boşlukta bölünecek ve şöyle yazdırılacaktır:bar,baz,qux,
IFS
ve bir setIFS
çok farklıdır. S4'ün cevabı kısmen yanlıştır: burada iç ayırıcılara dokunulmaz, sadece öncü ve takip edenlere dokunulur.