Bash'in “mapfile” filmine katılamazsınız… ama neden?


13

Sadece belirli bir dizindeki tüm dosyaları bir bash dizisine almak istiyorum (dosyaların hiçbirinin adında bir satırsonu olduğu varsayılarak):

Yani:

myarr=()
find . -maxdepth 1  -name "mysqldump*" | mapfile -t myarr; echo "${myarr[@]}"

Boş sonuç!

Geçici veya başka bir şekilde bir dosyayı kullanma dolambaçlı yolunu yaparsanız:

myarr=()
find . -maxdepth 1  -name "mysqldump*" > X
mapfile -t myarray < X
echo "${myarray[@]}"

Sonuç!

Ama neden mapfilebir borudan düzgün okumuyor?



Her yerde mükemmel cevaplar, herkese teşekkürler. Boru hattının yürütme stratejisinin (her bölüm bir spearat işleminde) nasıl "yukarı" sızdığını ve kodun görünen anlamını nasıl değiştirdiğini, temelde sessizce boruda görünen her değişkenin önüne "yerel" koyarak. Diğer programlar için çılgın tutkaldan başka bir şey olan bir dilde, umarım bu hata olur.
David Tonhofer

2
Kodu shellcheck'e verirseniz uyarılar alırsınız: SC2030 : "var modifikasyonu yereldir (boru hattının neden olduğu alt kabuklara )" ve SC2031 : "var bir alt kabukta değiştirilmiştir. Bu değişiklik kaybolabilir." . Mükemmel.
David Tonhofer

Kullanarak Neden findve mapfileburada hiç ve sadece basitçe myarr=(mysqldump*)? Bu, boşluklu ve yeni satırlı dosya adlarıyla bile çalışacaktır.
BlackJack

1
Sadece hiçbir dosya eşleşmesi durumunda dizi ile sona ermemek için nullglobseçeneği ( shopt -s nullglob) açmak zorunda olduğunu fark ettim . myarr=(mysqldump*)('mysqldump*')
David Tonhofer

Yanıtlar:


25

Gönderen man 1 bash:

Bir boru hattındaki her komut ayrı bir işlem olarak yürütülür (yani, alt kabukta).

Bu tür alt kabuklar değişkenleri ana kabuktan devralır, ancak bağımsızdır. Bu mapfile, orijinal komutunuzda kendi kendine çalıştığı anlamına gelir myarr. Sonra echo(borunun dışında olmak) boş yazdırır myarr(ana kabuk olan myarr).

Bu komut farklı çalışır:

find . -maxdepth 1 -name "mysqldump*" | { mapfile -t myarr; echo "${myarr[@]}"; }

Bu durumda mapfileve echoaynı şekilde çalışın myarr(ana kabuk değil myarr).

Ana kabuk değiştirmek için var myarrçalıştırmak zorunda mapfiletam olarak ana kabukta. Misal:

myarr=()
mapfile -t myarr < <(find . -maxdepth 1 -name "mysqldump*")
echo "${myarr[@]}"

Bir ziyaretçinin TL; DR momentine sahip olması durumunda Attie'nin yanıtında belirtildiği gibi "süreç ikamesi" bağlantısı eklendi.
David Tonhofer

11

Bash, bir alt çizgi ortamında bir boru hattının komutlarını çalıştırır, bu nedenle içinde gerçekleşen değişken atamalar vb., Kabuğun geri kalan kısmı tarafından görülemez.

Dash (Debian /bin/sh) ve busybox'lar shbenzerken, zsh ve ksh ana kabuğun son kısmını çalıştırır. Bash'te, shopt -s lastpipeaynısını yapmak için kullanabilirsiniz , ancak yalnızca iş kontrolü devre dışı bırakıldığında çalışır, bu nedenle varsayılan olarak etkileşimli kabuklarda çalışmaz.

Yani:

$ bash -c 'x=a; echo b | read x; echo $x'
a
$ bash -c 'shopt -s lastpipe; x=a; echo b | read x; echo $x'
b

( readve mapfileaynı sorunu yaşıyoruz.)

Alternatif olarak (ve Attie tarafından belirtildiği gibi ), genelleştirilmiş bir boru gibi çalışan ve Bash, ksh ve zsh'de desteklenen proses ikamesi kullanın .

$ bash -c 'x=a; read x < <(echo b); echo $x'
b

POSIX, bir boru hattının parçalarının alt kabuklarda çalışıp çalışmadığını belirtmeden bırakır, bu nedenle kabuklardan herhangi birinin "yanlış" olacağı söylenemez.


2
Bash'ın iş kontrolünü devre dışı bırakırsanız, lastpipe'ı etkileşimli bir kabukta da kullanabilirsiniz:set +m; shopt -s lastpipe; x=a; echo b | read x; echo $x; set -m
Cyrus

@Cyrus, ah doğru, ayrıntıları
unuturdum

9

Kamil'in belirttiği gibi, boru hattındaki her bir eleman ayrı bir süreçtir.

Farklı bir işlemde çalıştırmak için aşağıdaki işlem ikamesini kullanabilirsiniz findve mapfileçağrı, geçerli yorumcunuzda kalır ve myarrdaha sonra erişime izin verir :

myarr=()
mapfile -t myarr < <( find . -maxdepth 1  -name "mysqldump*" )
echo "${myarr[@]}"

b < <( a )a | bboru hattının nasıl bağlandığına benzer şekilde hareket eder - fark b" burada " yürütülü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.