Alan ayırma için ne zaman geçici bir IFS kullanabilirim?


19

Bash'da, diyelim ki var=a.b.c., o zaman:

$ IFS=. printf "%s\n" $var
a.b.c

Ancak, IFSbir dizi oluşturulurken böyle bir kullanım geçerli olur:

$ IFS=. arr=($var)
$ printf "%s\n" "${arr[@]}"
a
b
c

Bu çok uygun, elbette, ama bu nerede belgeleniyor? Bash belgelerindeki Diziler veya Sözcük Bölme bölümlerinin hızlı bir şekilde okunması her iki şekilde de bir gösterge vermez. Arandığında IFSaracılığıyla tek sayfalık belgelerde ya bu etkisi hakkında herhangi bir ipucu vermez.

Ne zaman güvenilir bir şekilde yapabileceğimden emin değilim:

IFS=x do something

Ve bunun IFSalan bölünmesini etkileyeceğini bekleyin.

Yanıtlar:


28

Temel fikir olduğunu VAR=VALUE some-commandsetleri VARiçin VALUEyürütülmesi için some-commandzaman some-commandharici bir komut olduğunu ve bundan daha fazla fantezi almaz. Bu sezgiyi bir kabuğun nasıl çalıştığı bilgisiyle birleştirirseniz, çoğu durumda doğru cevabı bulmalısınız. POSIX başvurusu, “Kabuk Komut Dili” bölümündeki “Basit Komutlar” dır .

Eğer some-commandbir olan dış komut , VAR=VALUE some-commandeşdeğerdir env VAR=VALUE some-command. VAR, dışına aktarılır some-commandve kabuktaki değeri (veya değer eksikliği) değişmez.

Eğer some-commandbir olan fonksiyon , daha sonra VAR=VALUE some-commandeşdeğerdir VAR=VALUE; some-command, yani yerinde atama kalıntıları işlevi sonra döndü, ve değişken ortama ihraç edilmez. Bunun nedeni Bourne kabuğunun tasarımı ile ilgilidir (ve daha sonra geriye dönük uyumluluk ile): bir işlevin yürütülmesi etrafında değişken değerleri kaydetmek ve geri yüklemek için hiçbir olanağı yoktu. Değişkenin dışa aktarılmaması anlamlıdır, çünkü bir işlev kabuğun kendisinde yürütülür. Bununla birlikte, ksh (ATT ksh93 ve pdksh / mksh dahil), bash ve zsh VAR, yalnızca işlevin yürütülmesi sırasında ayarlanan (ayrıca dışa aktarılır) daha kullanışlı davranışı uygular . Gelen ksh işlevi Ksh sözdizimi ile tanımlanması durumunda, bu yapılırfunction NAME …, standart sözdizimiyle tanımlanmışsa değil NAME (). In bash (ile çalıştırdığınızda, bu POSIX modunda, sadece bash modda yapılır POSIXLY_CORRECT=1). In zsh , bu yapılır posix_builtinsseçeneği ayarlı değil; bu seçenek varsayılan olarak ayarlanmamıştır emulate shveya veya ile açıktır emulate ksh.

Eğer some-commandbir yerleşiğidir, davranış yerleşiği türüne bağlıdır. Özel yapıların işlevleri gibi davranır. Özel yerleşikler, durum kabuğunu etkilediği için kabuğun içine uygulanması gerekenlerdir (örneğin breakkontrol akışını cdetkiler, geçerli dizini setetkiler, konumsal parametreleri ve seçenekleri etkiler…). Diğer yerleşikler yalnızca performans ve rahatlık için yerleşiktir (çoğunlukla - örneğin bash özelliği printf -vyalnızca bir yerleşik tarafından uygulanabilir) ve harici bir komut gibi davranırlar.

Atama eğer öyleyse, takma genişleme sonrasında gerçekleşir some-commandbir olduğunu takma , ne bulmak için ilk genişletin.

Tüm durumlarda atamanın, komut satırının kendisinde herhangi bir değişken ikame de dahil olmak üzere komut satırı ayrıştırıldıktan sonra gerçekleştirildiğini unutmayın. Yani var=a; var=b echo $varyazdırır a, çünkü $varödev yapılmadan önce değerlendirilir. Ve böylece IFS=. printf "%s\n" $vareski IFSdeğeri bölmek için kullanır $var.

Tüm komut türlerini kapsadım, ancak bir durum daha var : çalıştırılacak komut olmadığında , yani komut yalnızca atamalardan (ve muhtemelen yeniden yönlendirmelerden) oluşursa. Bu durumda, görev yerinde kalır . VAR=VALUE OTHERVAR=OTHERVALUEeşittir VAR=VALUE; OTHERVAR=OTHERVALUE. Böylece IFS=. arr=($var), IFSayarlanmış olarak kalır .. Kullanabileceğin yana $IFSatamaya arrzaten onun yeni değere sahip olduğu beklentisiyle, bu yeni değeri mantıklı IFSgenişletilmesi için kullanılır $var.

Özetle, kullanabileceğiniz IFSiçin geçici sadece saha bölünme:

  • yeni bir kabuk veya alt kabuk başlatarak (örn . değeri iki karakterden az olduğunda farklı davranmaları dışında third=$(IFS=.; set -f; set -- $var; echo "$3")karmaşık bir yöntemdir );third=${var#*.*.}var.
  • ksh içinde, IFS=. some-functionburada some-functionksh sözdizimi ile tanımlanır function some-function …;
  • bash ve zsh'da, IFS=. some-functionuyumluluk modunun aksine yerel modda çalıştıkları sürece.

" IFSkalır ." Eek. İlk kısmı okuduktan sonra, bu mantıklı, ama bu Q'yu göndermeden önce bunu beklemezdim.
muru

1
Bu farklı bir sorunun cevabı
schily

Birkaç yıl önce gelen bu cevapta bazı ek açıklamalar .
Ti Strga

6

@Gilles'ın cevabı gerçekten harika, karmaşık bir konuyu (ayrıntılı olarak) açıklıyor.

Ancak, neden bu komutun cevabına inanıyorum:

$ IFS=. printf "%s\n" $var
a.b.c

tüm komut satırının yürütülmeden önce ayrıştırılması basit bir fikirdir . Ve her "kelime" bir kez kabuk tarafından işlenir.
Atamaları gibi IFS=., geciktirilir (aşama 4 sonuncu):

4.- Her değişken atama genişletilecektir ...

komut çalıştırılmadan hemen önce ve bağımsız değişkenlerdeki tüm genişletmeler önce bu yürütülebilir satırı oluşturmak için işlenir:

$ IFS=. printf "%s\n" a.b.c           ## IFS=. goes to the environment.
a.b.c

Değeri $var, "eski" IFS ile a.b.ckomuttan önce genişletilir.printf argümanları verilir "%s\n"ve a.b.c.

Eval

Bir gecikme seviyesi şu yollarla tanıtılabilir eval:

$ IFS=. eval printf "'%s\n'" \$var
a
b
c

Satır ayrıştırılır (1. kez) ve 'IFS =.' çevreye şu şekilde ayarlanmıştır:

$ printf '%s\n' $var

Sonra tekrar buna ayrıştırılır:

$ printf '%s\n' a b c

Ve buna idam edildi:

a
b
c

Değeri $var (ABC) kullanımda IFS değeri ile bölünmüş olup: ..

çevre

Karmaşık ve zor kısım, çevrede geçerli olan şeydir !!!

Gilles'in cevabının ilk bölümünde bu çok iyi açıklandı.

Ek bir ayrıntı ile.

Bu komut yürütüldüğünde:

$ IFS=. arr=($var)

IFS'nin değeri mevcut ortamda korunur, evet:

$ printf '<%s>  ' "${arr[@]}" "$IFS"
<a>  <b>  <c>  <.> 

Tek bir ifade için IFS.

Ancak önlenebilir: IFS'yi tek bir ifade için ayarlama

$ IFS=. command eval arr\=\(\$var\)

$  printf '<%s>  ' "${arr[@]}" "$IFS"
<a>  <b>  <c>  < 
> 

2

İle ilgili sorunuz

var=a.b.c
IFS=. printf "%s\n" $var

bir köşe davasıdır.

Bunun nedeni, macro expansionkomuttaki kabuk değişkeninin ayarlanmasından önce gerçekleşmesidir IFS=..

Başka bir deyişle: $vargenişletildiğinde, önceki IFSdeğer etkin olur, sonra IFSolarak ayarlanır '.'.

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.