Dikkatlice hazırlanmış bir girdi metniyle bir örneğe bakalım:
text=' hello world\
foo\bar'
Bu iki satır, ilk önce bir boşlukla başlar ve bir ters eğik çizgiyle biter. İlk önce, etrafta herhangi bir önlem alınmadan neler olacağına bakalım read
(ancak herhangi bir genişleme riski olmadan printf '%s\n' "$text"
dikkatli bir şekilde baskı $text
yapmak için). (Aşağıda, $
kabuk istemidir.)
$ printf '%s\n' "$text" |
while read line; do printf '%s\n' "[$line]"; done
[hello worldfoobar]
read
ters eğik çizgi kadar yedim: ters eğik çizgi-newline yeni çizginin yok sayılmasına neden olur ve ters eğik çizgi-herhangi bir şey ilk ters eğik çizgiyi yok sayar. Ters eğik çizgilerin özel muamele görmesini önlemek için kullanırız read -r
.
$ printf '%s\n' "$text" |
while read -r line; do printf '%s\n' "[$line]"; done
[hello world\]
[foo\bar]
Bu daha iyi, beklendiği gibi iki çizgimiz var. İki satır neredeyse istenen içeriği içerir: arasındaki hello
ve arasındaki çift boşluk world
korunur, çünkü line
değişken içindedir . Öte yandan, ilk alan yenildi. Bunun nedeni read
, değişkenleri geçtiğin kadar çok kelime okuduğu için, son değişken satırın geri kalanını içermesi dışında - ama yine de ilk kelimeyle başlar, yani ilk boşluklar atılır.
Bu nedenle, her satırı tam anlamıyla okumak için, hiçbir kelime ayrılmasının olmadığından emin olmamız gerekir . Bunu, IFS
değişkeni boş bir değere ayarlayarak yaparız .
$ printf '%s\n' "$text" |
while IFS= read -r line; do printf '%s\n' "[$line]"; done
[ hello world\]
[foo\bar]
Biz set nasıl Not IFS
süresince özellikle read
yerleşik . IFS= read -r line
Setleri değişkeni IFS
spesifik olarak yürütülmesi için (boş değer) read
. Bu, genel basit komut sözdiziminin bir örneğidir : bunu bir komut adı ve argümanlarının izlediği (muhtemelen boş) değişken atama dizisi (ayrıca, istediğiniz noktaya yönlendirmelerde de atabilirsiniz). Yana read
yerleşik bir değişken gerçekte hiçbir zaman bir harici işlemin ortamda biter olduğu; Bununla birlikte, değeri , yürütüldüğü $IFS
sürece orada read
atadığımız şeydir¹. Bunun özel bir yerleşikread
olmadığını unutmayın , bu nedenle atama yalnızca süresi boyunca devam eder.
Bu nedenle IFS
, ona bağlı olabilecek diğer talimatların değerini değiştirmemeye özen gösteriyoruz . Bu kod, çevreleyen kodun IFS
başlangıçta neye ayarlanmış olursa olsun çalışır ve döngü içindeki kodun kullanılması durumunda herhangi bir soruna neden olmaz IFS
.
Dosyaları iki nokta üst üste ayrılmış bir yolda arayan bu kod snippet'iyle kontrast. Dosya adları listesi, bir dosyadan satır başına bir dosya adı okunur.
IFS=":"; set -f
while IFS= read -r name; do
for dir in $PATH; do
## At this point, "$IFS" is still ":"
if [ -e "$dir/$name" ]; then echo "$dir/$name"; fi
done
done <filenames.txt
Döngü olsaydı while IFS=; read -r name; do …
, o for dir in $PATH
zaman $PATH
kolon ayrılmış bileşenlere ayrılmaz. Kod IFS=; while read …
olsaydı , döngü gövdesinde IFS
ayarlanmamış daha da açık olurdu :
.
Tabii ki, IFS
çalıştırdıktan sonra değerini geri yüklemek mümkün olacaktır read
. Ancak bu, önceki çabanın bilinmesini gerektirir ki bu da ekstra bir çabadır. IFS= read
basit yoldur (ve uygun şekilde, aynı zamanda en kısa yoldur).
¹ Ve eğer read
tuzak çalışırken, tuzağa düşürülmüş bir sinyal tarafından kesilirse, bu POSIX tarafından belirtilmez ve pratikte kabuğa bağlıdır.
while IFS=X read
En bölmek değilX
, amawhile IFS=X; read
yapar ...