Sangat mudah digunakan split()
dalam JavaScript untuk memecah string menjadi sebuah array.
Bagaimana dengan skrip shell?
Katakanlah saya ingin melakukan ini:
$ script.sh var1_var2_var3
Ketika pengguna memberikan string tersebut var1_var2_var3
ke script.sh, di dalam skrip itu akan mengubah string menjadi seperti array
array=( var1 var2 var3 )
for name in ${array[@]}; do
# some code
done
shell
shell-script
string
AGamePlayer
sumber
sumber
shell
yang Anda gunakan, denganbash
yang dapat Anda lakukanIFS='_' read -a array <<< "${string}"
perl
dapat melakukannya juga. Ini bukan shell "murni", tetapi cukup umum.Jawaban:
Shell seperti Bourne / POSIX memiliki operator glob + split dan dipanggil setiap kali Anda meninggalkan ekspansi parameter (
$var
,$-
...), substitusi perintah ($(...)
), atau ekspansi aritmatika ($((...))
) tidak dikutip dalam konteks daftar.Sebenarnya, Anda dipanggil oleh kesalahan ketika Anda melakukan
for name in ${array[@]}
bukanfor name in "${array[@]}"
. (Sebenarnya, Anda harus berhati-hati bahwa memanggil operator seperti itu secara tidak sengaja merupakan sumber dari banyak bug dan kerentanan keamanan ).Operator itu dikonfigurasikan dengan
$IFS
parameter khusus (untuk memberi tahu karakter apa yang harus dipisah (meskipun berhati-hatilah bahwa ruang, tab, dan baris baru menerima perlakuan khusus di sana)) dan-f
opsi untuk menonaktifkan (set -f
) atau mengaktifkan (set +f
)glob
bagian.Perhatikan juga bahwa sementara
S
in$IFS
awalnya (dalam cangkang Bourne dari mana$IFS
) dari untuk Separator, dalam cangkang POSIX, karakter dalam$IFS
seharusnya lebih dilihat sebagai pembatas atau terminator (lihat di bawah untuk contoh).Jadi untuk dibagi
_
:Untuk melihat perbedaan antara pemisah dan pembatas , coba:
Itu akan membaginya menjadi
var1
danvar2
hanya (tidak ada elemen kosong tambahan).Jadi, untuk membuatnya mirip dengan JavaScript
split()
, Anda perlu langkah ekstra:(perhatikan bahwa itu akan membagi elemen kosong
$string
menjadi 1 (bukan 0 ), seperti JavaScriptsplit()
).Untuk melihat tab perawatan khusus, ruang dan baris baru terima, bandingkan:
(di mana Anda dapatkan
var1
danvar2
) dengandi mana Anda mendapatkan:
''
,var1
,''
,var2
,''
.Perhatikan bahwa
zsh
shell tidak memanggil operator glob + split yang secara implisit seperti itu kecuali dalamsh
atauksh
emulasi. Di sana, Anda harus memohonnya dengan jelas.$=string
untuk bagian split,$~string
untuk bagian glob ($=~string
untuk keduanya), dan juga memiliki operator split di mana Anda dapat menentukan pemisah:atau untuk melestarikan elemen kosong:
Perhatikan bahwa ada
s
adalah untuk membelah , bukan pembatasan (juga dengan$IFS
, yang dikenal POSIX ketidaksesuaian darizsh
). Ini berbeda dari JavaScriptsplit()
karena string kosong dipecah menjadi elemen 0 (bukan 1).Perbedaan penting dengan
$IFS
-sitting adalah bahwa${(s:abc:)string}
splits padaabc
string, sedangkan denganIFS=abc
, yang akan terpecaha
,b
atauc
.Dengan
zsh
danksh93
, perlakuan khusus yang diterima ruang, tab, atau baris baru dapat dihapus dengan menggandakannya$IFS
.Sebagai catatan bersejarah, cangkang Bourne (leluhur atau cangkang POSIX modern) selalu menghilangkan elemen-elemen yang kosong. Itu juga memiliki sejumlah bug yang terkait dengan pemisahan dan perluasan $ @ dengan nilai-nilai non-default
$IFS
. MisalnyaIFS=_; set -f; set -- $@
tidak akan setara denganIFS=_; set -f; set -- $1 $2 $3...
.Berpisah pada regexps
Sekarang untuk sesuatu yang lebih dekat dengan JavaScript
split()
yang dapat terpecah pada ekspresi reguler, Anda harus bergantung pada utilitas eksternal.Dalam peti alat POSIX,
awk
memilikisplit
operator yang dapat membagi pada ekspresi reguler yang diperluas (yang lebih atau kurang merupakan subset dari ekspresi reguler Perl-seperti yang didukung oleh JavaScript).The
zsh
shell memiliki builtin dukungan untuk ekspresi Perl-kompatibel reguler (di-nyazsh/pcre
modul), tetapi menggunakannya untuk membagi string, meskipun mungkin relatif rumit.sumber
$PATH
di:
) sebaliknya, biasanya Anda ingin melestarikan elemen kosong. Perhatikan bahwa dalam cangkang Bourne, semua karakter menerima perlakuan khusus,ksh
mengubahnya agar hanya yang kosong (hanya spasi, tab, dan baris baru) yang diperlakukan secara khusus.zsh
perawatan dengan string berisi 2 karakter atau lebih${(s:string:)var}
? Jika ditambahkan, saya dapat menghapus jawaban saya :)S
singkatan dari Separator , bukan pembatas . Paling tidak, itulah yang dikatakan manual bash saya.$IFS
berasal dari shell Bourne di mana ia pemisah , ksh mengubah perilaku tanpa mengubah nama. Saya menyebutkan bahwa untuk menekankan bahwasplit+glob
(kecuali dalam zsh atau pdksh) tidak hanya terpecah lagi.Ya, gunakan
IFS
dan atur ke_
. Kemudian gunakanread -a
untuk menyimpan ke dalam array (-r
mematikan ekspansi backslash). Perhatikan bahwa ini khusus untuk bash; ksh dan zsh memiliki fitur serupa dengan sintaks yang sedikit berbeda, dan sh polos tidak memiliki variabel array sama sekali.Dari
man bash
:Perhatikan bahwa
read
berhenti di baris baru pertama. Lewati-d ''
untukread
menghindari itu, tetapi dalam hal itu, akan ada baris baru tambahan pada akhirnya karena<<<
operator. Anda dapat menghapusnya secara manual:sumber
$r
tidak mengandung karakter baris baru atau garis miring terbalik. Perhatikan juga bahwa itu hanya akan berfungsi di versibash
shell terbaru.bash
,read -a
diperkenalkan di bash 4, kan?<<<
hanya ditambahkan baru-baru inibash
tetapi tampaknya sudah ada sejak 2.05b (2002).read -a
bahkan lebih tua dari itu.<<<
berasal darizsh
dan didukung olehksh93
(dan mksh dan yash) juga tetapiread -a
spesifik bash (ada-A
di ksh93, yash dan zsh).