Jawaban:
Gunakan cutdengan _sebagai pembatas bidang dan dapatkan bidang yang diinginkan:
A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"
Anda juga bisa menggunakan echodan mem-pipe bukannya string Here:
A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"
Contoh:
$ s='one_two_three_four_five'
$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two
$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four
$ echo $FILE my_user/my_folder/file.csv $ A="$(cut -d'/' -f2 <<<"$FILE")" $ echo $A [file]* Apakah Anda tahu apa yang terjadi di sini?
echo "${s##*_}"
Hanya menggunakan konstruksi sh POSIX, Anda bisa menggunakan konstruksi substitusi parameter untuk mengurai satu pembatas pada satu waktu. Perhatikan bahwa kode ini mengasumsikan bahwa ada jumlah bidang yang diperlukan, jika tidak, bidang terakhir diulang.
string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"
Atau, Anda dapat menggunakan substitusi parameter yang tidak dikutip dengan ekspansi wildcard dinonaktifkan dan IFSdiatur ke karakter pembatas (ini hanya bekerja jika pembatas adalah karakter non-spasi tunggal atau jika urutan spasi apa pun adalah pembatas).
string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS
Ini mengacaukan parameter posisi. Jika Anda melakukan ini dalam suatu fungsi, hanya parameter posisi fungsi yang terpengaruh.
Namun pendekatan lain adalah dengan menggunakan readbuiltin.
IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
unset IFStidak kembali IFSke default. Jika setelah itu seseorang OldIFS="$IFS"akan memiliki nilai nol di dalam OldIFS. Juga, diasumsikan bahwa nilai IFS sebelumnya adalah default, yang sangat mungkin (dan berguna) untuk tidak. Satu-satunya solusi yang benar adalah menyimpan old="$IFS"dan mengembalikan dengan IFS = "$ old". Atau ... gunakan sub-shell (...). Atau, lebih baik lagi, baca jawaban saya.
unset IFStidak mengembalikan IFSke nilai default, tetapi mengembalikan pemisahan bidang ke efek default. Ya, ini adalah batasan, tetapi biasanya yang dapat diterima dalam praktik. Masalah dengan subkulit adalah kita perlu mengambil data darinya. Saya memang menunjukkan solusi yang tidak mengubah keadaan pada akhirnya, dengan read. (Ini bekerja di shell POSIX, tetapi IIRC tidak di shell Bourne karena ia akan menjalankan readdalam subkulit karena dokumen di sini.) Menggunakan <<<seperti pada jawaban Anda adalah varian yang hanya bekerja di ksh / bash / zsh.
user/my_folder/[this_is_my_file]*? Apa yang saya dapatkan ketika saya mengikuti langkah-langkah ini adalah[this_is_my_file]*
/.
Ingin melihat awkjawaban, jadi ini satu:
A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')
awk -F_ '{print $NF}' <<< 'one_two_3_4_five'
Cara paling sederhana (untuk kerang dengan <<<) adalah:
IFS='_' read -r a second a fourth a <<<"$string"
Menggunakan variabel temporal $aalih-alih $_karena satu shell mengeluh.
Dalam skrip lengkap:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<<"$string"
echo "$second $fourth"
Tidak ada perubahan IFS, bukan masalah dengan set -f(Perluasan pathname) Tidak ada perubahan pada parameter posisi ("$ @").
Untuk solusi portabel untuk semua shell (ya, semua POSIX termasuk) tanpa mengubah IFS atau set -f, gunakan (setara dengan sedikit lebih kompleks) heredoc:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_
echo "$second $fourth"
Memahami bahwa solusi ini (baik di sini-doc dan penggunaan <<<akan menghapus semua baris baru.
Dan bahwa ini dirancang untuk konten variabel "satu liner."
Solusi untuk multi-liner dimungkinkan tetapi membutuhkan konstruksi yang lebih kompleks.
Solusi yang sangat sederhana dimungkinkan di versi bash 4.4
readarray -d _ -t arr <<<"$string"
echo "array ${arr[1]} ${arr[3]}" # array numbers are zero based.
Tidak ada padanan untuk shell POSIX, karena banyak shell POSIX tidak memiliki array.
Untuk cangkang yang memiliki larik mungkin sesederhana:
(diuji bekerja di attsh, lksh, mksh, ksh, dan bash)
set -f; IFS=_; arr=($string)
Tetapi dengan banyak pipa tambahan untuk menjaga dan mengatur ulang variabel dan opsi:
string='one_* *_three_four_five'
case $- in
*f*) noglobset=true; ;;
*) noglobset=false;;
esac
oldIFS="$IFS"
set -f; IFS=_; arr=($string)
if $noglobset; then set -f; else set +f; fi
echo "two=${arr[1]} four=${arr[3]}"
Di zsh, array dimulai pada 1, dan tidak memisah string secara default.
Jadi beberapa perubahan perlu dilakukan untuk mendapatkan ini berfungsi di zsh.
read sederhana selama OP tidak ingin mengekstraksi elemen ke-76 dan ke-127 dari string panjang ...
readarraybisa lebih mudah digunakan untuk situasi itu.
Dengan zshAnda dapat membagi string (on _) menjadi array:
elements=(${(s:_:)string})
dan kemudian mengakses setiap elemen melalui indeks array:
print -r ${elements[4]}
Perlu diingat bahwa dalam indeks arrayzsh (tidak seperti ksh/ bash) mulai dari 1 .
set -fperingatan ke solusi pertama. ... tanda bintang *mungkin?
set -f? Saya tidak menggunakan read/ IFS. Coba solusi saya dengan string seperti *_*_*atau apa pun ...
Contoh awk lainnya; lebih mudah dimengerti.
A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`
... and so on...
Dapat digunakan dengan variabel juga.
Misalkan:
this_str = "one_two_three_four_five"
Maka yang berikut berfungsi:
A = `echo $ {this_str} | awk -F_ '{print $ 1}' `
B =` echo $ {this_str} | awk -F_ '{print $ 2}' `
C =` echo $ {this_str} | awk -F_ '{print $ 3}' `
... dan seterusnya ...