Saya telah menulis skrip sampel untuk memisahkan string tetapi tidak berfungsi seperti yang diharapkan
#!/bin/bash
IN="One-XX-X-17.0.0"
IFS='-' read -r -a ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
echo "Element:$i"
done
#split 17.0.0 into NUM
IFS='.' read -a array <<<${ADDR[3]};
for element in "${array[@]}"
do
echo "Num:$element"
done
keluaran
One
XX
X
17.0.0
17 0 0
tapi saya berharap hasilnya:
One
XX
X
17.0.0
17
0
0
bash
shell-script
lfs
pengguna112232
sumber
sumber
Jawaban:
Perbaiki, (lihat juga jawaban S. Chazelas untuk latar belakang), dengan output yang masuk akal:
Keluaran:
Catatan:
Lebih baik untuk menempatkan bersyarat 2 lingkaran di dalam 1 lingkaran.
bash
substitusi pola ("${i//.}"
) memeriksa apakah ada.
elemen. (case
Pernyataan mungkin lebih sederhana, meskipun kurang mirip dengan kode OP .)read
ing$array
dengan memasukkan<<< "${ADDR[3]}"
kurang umum daripada<<< "$i"
. Ini menghindari perlu tahu elemen mana yang memiliki.
s.Kode ini mengasumsikan bahwa pencetakan " Elemen: 17.0.0 " tidak disengaja. Jika Perilaku itu dimaksudkan, ganti loop utama dengan:
sumber
case $i in (*.*) ...
akan menjadi cara yang lebih kanonik untuk memeriksa yang$i
berisi.
(dan juga portabel untuksh
). Jika Anda menyukai kshisme, lihat juga:[[ $i = *.* ]]
case
dalam catatan di akhir, tapi kami setuju. (Karena OP menggunakan keduanya<<<
dan array , ini bukansh
pertanyaan besar.)Di versi lama
bash
Anda harus mengutip variabel setelahnya<<<
. Itu diperbaiki di 4.4. Dalam versi yang lebih lama, variabel akan dipecah pada IFS dan kata-kata yang dihasilkan bergabung di ruang sebelum disimpan dalam file sementara yang membentuk<<<
pengalihan itu.Di 4.2 dan sebelumnya, ketika mengarahkan ulang builtin seperti
read
ataucommand
, pemisahan itu bahkan akan mengambil IFS untuk builtin itu (4.3 memperbaiki itu):Yang diperbaiki di 4.3:
Namun
$a
masih ada pemisahan kata di sana:Dalam 4.4:
Untuk portabilitas ke versi yang lebih lama, kutip variabel Anda (atau gunakan dari
zsh
mana<<<
asalnya dan yang tidak memiliki masalah itu)Perhatikan bahwa pendekatan untuk memecah string hanya berfungsi untuk string yang tidak mengandung karakter baris baru. Juga mencatat bahwa
a..b.c.
akan terpecah menjadi"a"
,""
,"b"
,"c"
(tidak ada mengosongkan elemen terakhir).Untuk membagi string sewenang-wenang, Anda dapat menggunakan operator split + glob sebagai gantinya (yang akan menjadikannya standar dan menghindari menyimpan konten variabel dalam file temp seperti
<<<
halnya):atau:
The
''
adalah untuk melestarikan elemen kosong tertinggal jika ada. Itu juga akan membagi kosong$var
menjadi satu elemen kosong.Atau gunakan shell dengan operator pemisahan yang tepat:
zsh
:rc
:fish
sumber
Dengan awk akan dikenakan biaya satu baris:
-F'[-.]'
- pemisah bidang berdasarkan beberapa karakter, dalam kasus kami-
dan.
Hasil:
sumber
IFS=-. read -r a array <<< "$IN"
Di sini cara saya:
hasil seperti yang diharapkan:
sumber
$IN
memanggil operator + gumpal split. Di sini, Anda tidak ingin bagian glob (cobaIN=*-*-/*-17.0.0
misalnya), jadi Anda ingin melakukannyaset -o noglob
sebelum memintanya. Lihat jawaban saya untuk detailnya.IFS
dan mengaturnya secara global. Anda benar-benar hanya ingin mengubah nilaiIFS
kapan$IN
diperluas, dan Anda juga tidak ingin ekspansi pathname dilakukan pada ekspansi. Lebih jauh,OIFS=$IFS
tidak membedakan antara case ketikaIFS
diatur ke string kosong, dan kapanIFS
benar-benar tidak disetel.