$ '\ 0' neden '' ile aynı?


10

Birkaç dosyayla bir şeyler yapmanın yaygın bir yolu - ve bunun için bana vurmayın:

for f in $(ls); do 

Şimdi, boşluklara veya diğer garip karakterlere sahip dosyalara karşı güvende olmak için naif bir yol olurdu:

find . -type f -print0 | while IFS= read -r -d '' file; 

Burada, -d ''ASCII NUL'u olduğu gibi ayarlamak için kısadır -d $'\0'.

Ama neden böyle? Neden ''ve $'\0'aynı? Bu boş bir dize ile Bash'ın C köklerinden dolayı her zaman boş bırakılır mı?


"Saf" yoldan bahsederken, bunu yapmanın daha iyi bir yolu var mı?
iruvar

2
Bu arada, bir dizi dosya üzerinde yinelenen güvenli işlemler yapmak istiyorsanız - for f in *ayrıştırmak yerine kullanın ls.

@htor for i in $(ls)Çok aptalca olduğunu biliyorum - Burada kötü bir örnek olarak kullandığım için neredeyse utanıyorum.
13'te

@ChandraRavoori Evet, örneğin, find … -execbunun yerine böyle bir for döngüsü kullanacağınız çoğu durumda çalışan dosyaların etrafında döngü yerine kullanmak. Burada findsizin için her şeyi halleder.
slhck

@slhck, teşekkürler. Okunabilirlik nedenlerinden ötürü bir döngünün tercih edilebileceği her dosyada çok adımlı işlemleri içeren durumlar ne olacak? Yukarıdaki "saf yoldan" daha iyi bir döngü seçeneği var mı?
iruvar

Yanıtlar:


10

man page of bashokur:

          -d delim
                 The first character of delim is  used  to  terminate  the
                 input line, rather than newline.

Dizeler genellikle null sonlandırıldığından, boş bir dizenin ilk karakteri null bayttır. - Bana mantıklı geldi. :)

Kaynak şunu okur:

static unsigned char delim;
[...]
    case 'd':
      delim = *list_optarg;
      break;

Boş bir dize delimiçin sadece boş bayt kullanılır.


"Dizeler genellikle null sonlandırılır" dediğinizde, POSIX ortamında bir yerde durum böyle değil mi? Okul için C öğrenmeye başladığım zamanlardan itibaren, elbette bunu varsaymak mantıklıdır; Sadece kontrol ediyordum.
slhck

Ancak, herhangi bir dizginin keyfi olarak çok sayıda boş dizgi içerdiği düşünülebilir, örneğin '' ve "X'i birleştirirseniz" X "elde edersiniz. Böylece, ilk alt dize bashının karşılaştığı boş dize olduğunu iddia edebilirsiniz. Örneğin, javascript dosyalarında boş bir dize kullanırsanız, split()bu karakter her karakter arasında bölünecektir. "Tarihsel nedenlerden ötürü" elde edebileceğimiz en iyi açıklama olabileceğinden şüpheleniyorum.
bağışlar başarıyla

Aslında tam olarak değil "birleştirerek" Çünkü C tarzı '\0'ile 'X\0'sizi vermelidir 'X\0', eğer bitti hakkı. Bunun JavaScript @don
slhck

Kaynağı eklediğiniz için teşekkürler michas. delim = *list_optarg;neden bu şekilde olduğunu netleştirir.
slhck

@slhck: Üzgünüm, kendimi netleştirmedim. "Neden ''ve $'\0'aynı?" Diye sordunuz, michas "kodun yaptığı şey" in yakın açıklamasını yaptı. Eşit derecede makul gördüğüm boş dizgeyi ele almanın alternatif bir yolunu belirledim ve birini veya diğerini seçmenin sadece bir kongre veya olay meselesi olduğunu önerdim.
donothingsuccessfully

6

Bash'da birbirini telafi eden iki eksiklik vardır.

Yazdığınızda $'\0', bu dahili olarak boş dizeyle aynı şekilde işlenir. Örneğin:

$ a=$'\0'; echo ${#a}
0

Budur içten bash mağazalarında çünkü tüm dizeleri C olan dizeleri, boş sonlandırılmış - boş bayt işaretleri dize sonu. Bash, dizeyi sessizce ilk boş bayta keser (dizenin bir parçası değildir!).

# a=$'foo\0bar'; echo "$a"; echo ${#a}
foo
3

Bir dizeyi yerleşik -dseçeneğine argüman olarak readilettiğinizde, bash yalnızca dizenin ilk baytına bakar. Ancak dizenin boş olup olmadığını kontrol etmez. Dahili olarak, boş bir dize, yalnızca bir boş bayt içeren 1 öğeli bir bayt dizisi olarak temsil edilir. Yani dizenin ilk baytını okumak yerine, bash bu boş baytı okur.

Daha sonra, dahili olarak, yapının arkasındaki makineler readboş baytlarla iyi çalışır; sınırlayıcıyı bulana kadar bayt bayt okumaya devam eder.

Diğer mermiler farklı davranırlar. Örneğin, kül ve ksh girdiyi okurken boş baytları yok sayar. Ksh ile ksh -d ""bir satırsonuna kadar okur. Kabuklar, ikili verilerle değil metinle iyi başa çıkmak için tasarlanmıştır. Zsh bir istisnadır: null baytlar dahil rastgele baytlarla başa çıkabilen bir dize temsili kullanır; zsh, $'\0'uzunluk 1 dizesidir (ama read -d ''garip bir şekilde davranır read -d $'\0').


readBash 4.3'teki davranış, artık boş bayt atlayacak şekilde değişti. Örneğin , yerine read x< <(printf a\\0a)ayarlanır . xaaa
Lri
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.