masalah readarray (atau pipa)

19

Saya terjebak dengan perilaku readarrayperintah yang aneh .

Amerika man bashSerikat:

readarray
     Read lines from the standard input into the indexed array variable array

tetapi skrip ini tidak berfungsi (array kosong):

unset arr; (echo a; echo b; echo c) | readarray arr; echo ${#arr[@]}
unset arr; cat /etc/passwd | readarray arr;  echo ${#arr[@]}

Dan ini bekerja:

unset arr; readarray arr < /etc/passwd ;  echo ${#arr[@]}
unset arr; mkfifo /tmp/fifo; (echo a; echo b; echo c) > /tmp/fifo & mapfile arr < /tmp/fifo ; echo ${#arr[@]}

Ada apa dengan pipa?

dchirikov
sumber

Jawaban:

15

Mungkin mencoba:

unset arr
printf %s\\n a b c | {
    readarray arr
    echo ${#arr[@]}
}

Saya berharap ini akan berhasil, tetapi saat Anda melangkah keluar dari konteks {shell terakhir ; }di akhir |pipa di sana Anda akan kehilangan nilai variabel Anda. Ini karena masing- |masing |proses terpisah dalam suatu |pipa dijalankan dalam sebuah (subkulit ). Jadi barang Anda tidak berfungsi karena alasan yang sama:

( arr=( a b c ) ) ; echo ${arr[@]}

... tidak - nilai variabel diatur dalam proses shell yang berbeda dari yang Anda panggil.

mikeserv
sumber
23

Untuk memastikan readarrayperintah dieksekusi di shell saat ini, gunakan subtitusi proses sebagai pengganti pipa:

readarray arr < <( echo a; echo b; echo c )

atau (jika bash4.2 atau lebih baru) menggunakan lastpipeopsi shell:

shopt -s lastpipe
( echo a; echo b; echo c ) | readarray arr
chepner
sumber
1
Keren. Ini bekerja, tetapi apa sebenarnya proses substitusi? Dan apa artinya memiliki < <2 panah?
CMCDragonkai
1
Lihat bashhalaman manual. Singkatnya, ini sintaksis untuk memperlakukan pipa sebagai deskriptor file. < <(...)artinya mengarahkan redirect (yang pertama <) dari output perintah di dalamnya <(...). Serupa, > >(...)akan melewati output standar ke input standar dari pipa di dalam >(...). Anda tidak perlu menggunakan pengalihan dengan substitusi proses. cat <( echo a b c )berfungsi juga.
chepner
Kedua opsi ini menghasilkan hasil yang tidak diinginkan bagi saya, di mana setiap item array mempertahankan akhir baris di akhir setiap string. Sedangkan jawaban oleh smac89 tidak memiliki masalah ini.
Lutut
3

readarray dapat juga membaca dari stdin, jadi:

readarray arr <<< "$(echo a; echo b; echo c)"; echo ${#arr[@]}
smac89
sumber