Saya perlu membaca output dari sebuah perintah dalam skrip saya menjadi sebuah array. Perintahnya adalah, misalnya:
ps aux | grep | grep | x
dan memberikan output baris demi baris seperti ini:
10
20
30
Saya perlu membaca nilai dari output perintah ke dalam array, dan kemudian saya akan melakukan beberapa pekerjaan jika ukuran array kurang dari tiga.
Jawaban:
Jawaban yang lain akan pecah jika output dari perintah mengandung spasi (yang agak sering) atau gumpal karakter seperti
*
,?
,[...]
.Untuk mendapatkan output dari sebuah perintah dalam sebuah array, dengan satu baris per elemen, pada dasarnya ada 3 cara:
Dengan penggunaan Bash≥4
mapfile
— yang paling efisien:Jika tidak, loop membaca output (lebih lambat, tapi aman):
Seperti yang disarankan oleh Charles Duffy di komentar (terima kasih!), Berikut ini mungkin bekerja lebih baik daripada metode loop di nomor 2:
Harap pastikan Anda menggunakan formulir ini persis, yaitu, pastikan Anda memiliki yang berikut:
IFS=$'\n'
pada baris yang sama denganread
pernyataan: ini hanya akan menyetel variabel lingkunganIFS
untukread
pernyataan saja. Jadi itu tidak akan memengaruhi seluruh skrip Anda sama sekali. Tujuan dari variabel ini adalah untuk memberitahuread
untuk menghentikan aliran pada karakter EOL\n
.-r
: ini penting. Ini memberitahuread
untuk tidak menafsirkan garis miring terbalik sebagai urutan pelarian.-d ''
: harap perhatikan jarak antara-d
opsi dan argumennya''
. Jika Anda tidak meninggalkan spasi di sini, maka''
tidak akan pernah terlihat, karena akan hilang pada langkah penghapusan kutipan saat Bash mengurai pernyataan tersebut. Ini memberitahuread
untuk berhenti membaca pada byte nol. Beberapa orang menulisnya sebagai-d $'\0'
, tetapi sebenarnya tidak terlalu perlu.-d ''
lebih baik.-a my_array
memberitahuread
untuk mengisi larikmy_array
saat membaca aliran.printf '\0'
pernyataan setelahmy_command
, sehinggaread
mengembalikan0
; sebenarnya bukan masalah besar jika Anda tidak melakukannya (Anda hanya akan mendapatkan kode pengembalian1
, yang tidak masalah jika Anda tidak menggunakannyaset -e
- yang seharusnya tidak Anda gunakan ), tetapi ingatlah itu. Ini lebih bersih dan lebih tepat secara semantik. Perhatikan bahwa ini berbeda dariprintf ''
, yang tidak menghasilkan apa pun.printf '\0'
mencetak byte nol, diperlukan olehread
untuk dengan senang hati berhenti membaca di sana (ingat-d ''
opsinya?).Jika Anda bisa, misalnya, jika Anda yakin kode Anda akan berjalan di Bash≥4, gunakan metode pertama. Dan Anda juga bisa melihatnya lebih pendek.
Jika Anda ingin menggunakan
read
, loop (metode 2) mungkin memiliki keunggulan dibandingkan metode 3 jika Anda ingin melakukan beberapa pemrosesan saat baris dibaca: Anda memiliki akses langsung ke sana (melalui$line
variabel dalam contoh yang saya berikan), dan Anda juga memiliki akses ke baris yang sudah dibaca (melalui array${my_array[@]}
dalam contoh yang saya berikan).Perhatikan bahwa
mapfile
menyediakan cara agar callback mengevaluasi pada setiap baris yang dibaca, dan pada kenyataannya Anda bahkan dapat memberitahukannya untuk hanya memanggil callback ini setiap baris N yang dibaca; lihathelp mapfile
dan opsi-C
dan di-c
dalamnya. (Pendapat saya tentang ini adalah bahwa ini sedikit kikuk, tetapi terkadang dapat digunakan jika Anda hanya memiliki hal-hal sederhana yang harus dilakukan - Saya tidak begitu mengerti mengapa ini bahkan diterapkan di tempat pertama!).Sekarang saya akan memberi tahu Anda mengapa metode berikut:
rusak jika ada spasi:
Kemudian beberapa orang kemudian akan merekomendasikan penggunaan
IFS=$'\n'
untuk memperbaikinya:Tapi sekarang mari kita gunakan perintah lain, dengan globs :
Itu karena saya memiliki file bernama
t
di direktori saat ini ... dan nama file ini cocok dengan glob[three four]
... pada titik ini beberapa orang akan merekomendasikan penggunaanset -f
untuk menonaktifkan globbing: tetapi lihatlah: Anda harus mengubahIFS
dan menggunakanset -f
untuk dapat memperbaiki sebuah teknik rusak (dan Anda bahkan tidak benar-benar memperbaikinya)! ketika melakukan itu kita benar-benar melawan shell, bukan bekerja dengan shell .di sini kami bekerja dengan cangkangnya!
sumber
mapfile
sebelumnya, itulah yang telah saya lewatkan selama bertahun-tahun. Saya rasa versi terbarubash
memiliki begitu banyak fitur baru yang bagus, saya hanya perlu menghabiskan beberapa hari membaca dokumen dan menuliskan lembar contekan yang bagus.< <(command)
dalam skrip shell, baris shebang harus#!/bin/bash
- jika dijalankan sebagai#!/bin/sh
, bash akan keluar dengan kesalahan sintaks.bash my_script.sh
dan bukan perintah shsh my_script.sh
sh
dandash
tidak tahu tentang array sama sekali, kecuali, tentu saja, untuk$@
array parameter posisi ).IFS=$'\n' read -r -d '' -a my_array < <(my_command && printf '\0')
- keduanya berfungsi dengan benar di bash 3.x, dan juga melewati status keluar gagal darimy_command
keread
.Kamu bisa memakai
untuk menyimpan output dari perintah
<command>
ke dalam arraymy_array
.Anda dapat mengakses panjang array itu menggunakan
Sekarang panjangnya disimpan
my_array_length
.sumber
VAR="$(<command>)"
dan kemudianmy_array=("$VAR")
ataumy_array+=("$VAR")
Bayangkan Anda akan meletakkan file dan nama direktori (di bawah folder saat ini) ke sebuah array dan menghitung itemnya. Naskahnya akan seperti;
Atau, Anda dapat mengulangi array ini dengan menambahkan skrip berikut:
Harap dicatat bahwa ini adalah konsep inti dan masukan dianggap telah dibersihkan sebelumnya, yaitu menghapus karakter tambahan, menangani String kosong, dan lain-lain (yang berada di luar topik utas ini).
sumber