Diberikan nama file dalam formulir someletters_12345_moreleters.ext
, saya ingin mengekstrak 5 digit dan memasukkannya ke dalam variabel.
Jadi untuk menekankan intinya, saya memiliki nama file dengan jumlah x karakter kemudian urutan lima digit dikelilingi oleh garis bawah tunggal di kedua sisi kemudian satu set x jumlah karakter. Saya ingin mengambil nomor 5 digit dan memasukkannya ke dalam variabel.
Saya sangat tertarik dengan sejumlah cara berbeda yang dapat dilakukan.
abc_12345_def_67890_ghi_def
adalah input yang valid. Apa yang kamu inginkan terjadi? Mari kita asumsikan hanya ada satu urutan 5 digit. Anda masih memilikiabc_def_12345_ghi_jkl
atau1234567_12345_1234567
atau12345d_12345_12345e
sebagai input yang valid berdasarkan definisi input Anda dan sebagian besar jawaban di bawah tidak akan menangani hal ini._
pembatas yang sama , input yang berisi string target hanya sekali, dll.). Jawaban terbaik (paling umum dan tercepat) , setelah 10 tahun, hanya 7 naik, sedangkan jawaban terbatas lainnya memiliki ratusan. Membuat saya kehilangan kepercayaan pada pengembang 😞Jawaban:
Gunakan potong :
Lebih umum:
sumber
echo
kecuali Anda tahu pasti bahwa variabel tidak dapat berisi spasi putih atau karakter metak shell. Lihat lebih lanjut stackoverflow.com/questions/10067266/…Jika x konstan, ekspansi parameter berikut melakukan ekstraksi substring:
di mana 12 adalah offset (berbasis nol) dan 5 adalah panjangnya
Jika garis bawah di sekitar digit adalah satu-satunya di input, Anda dapat menghapus awalan dan akhiran (masing-masing) dalam dua langkah:
Jika ada garis bawah lainnya, itu mungkin layak, meskipun lebih rumit. Jika ada yang tahu bagaimana melakukan kedua ekspansi dalam satu ekspresi, saya juga ingin tahu.
Kedua solusi yang disajikan adalah bash murni, tanpa melibatkan proses pemijahan, karenanya sangat cepat.
sumber
bash: ${${a#*_}%_*}: bad substitution
di GNU bash 4.2.45 saya.sh
skrip, yang mungkin putus-putus. Pada titik ini saya tidak bisa membuatnya bekerja lagi.:-
substitusi "Gunakan Nilai Default". Jadi${a: -12:5}
menghasilkan 5 karakter 12 karakter dari akhir, dan${a: -12:-5}
7 karakter antara akhir-12 dan akhir-5.Solusi generik di mana nomornya bisa di mana saja dalam nama file, menggunakan yang pertama dari urutan seperti itu:
Solusi lain untuk mengekstrak persis bagian dari variabel:
Jika nama file Anda selalu memiliki format,
stuff_digits_...
Anda dapat menggunakan awk:Namun solusi lain untuk menghapus semuanya kecuali angka, gunakan
sumber
coba saja gunakan
cut -c startIndx-stopIndx
sumber
startIndx-$((lastIndx-1))
start=5;stop=9; echo "the rain in spain" | cut -c $start-$(($stop-1))
git log --oneline | head -1 | cut -c 9-(end -1)
line=
git log --oneline | kepala -1` && echo $ line | cut -c 9 - $ (($ {# line} -1)) `tetapi dalam kasus khusus ini, mungkin lebih baik menggunakan sed asgit log --oneline | head -1 | sed -e 's/^[a-z0-9]* //g'
Jika seseorang menginginkan informasi yang lebih teliti, Anda juga dapat mencarinya di man bash seperti ini
Hasil:
sumber
${var: -4}
Begini cara saya melakukannya:
Penjelasan:
Khusus bash:
[[ ]]
menunjukkan ekspresi kondisional=~
menunjukkan kondisi adalah ekspresi reguler&&
rantai perintah jika perintah sebelumnya berhasilEkspresi Reguler (RE):
_([[:digit:]]{5})_
_
adalah literal untuk menandai batas-batas pencocokan / jangkar untuk string yang cocok()
buat grup tangkap[[:digit:]]
adalah kelas karakter, saya pikir itu berbicara sendiri{5}
berarti tepat lima karakter sebelumnya, kelas (seperti dalam contoh ini), atau grup harus cocokDalam bahasa Inggris, Anda dapat menganggapnya berperilaku seperti ini:
FN
string diulang karakter demi karakter sampai kami melihat titik_
di mana grup tangkapan dibuka dan kami berusaha untuk mencocokkan lima digit. Jika pencocokan itu berhasil ke titik ini, grup tangkap menyimpan lima digit yang dilintasi. Jika karakter berikutnya adalah_
, kondisinya berhasil, grup tangkap tersediaBASH_REMATCH
, danNUM=
pernyataan berikutnya dapat dijalankan. Jika ada bagian dari pencocokan yang gagal, rincian yang disimpan dibuang dan karakter demi pemrosesan karakter berlanjut setelah_
. mis. jika diFN
mana_1 _12 _123 _1234 _12345_
, akan ada empat awal yang salah sebelum menemukan kecocokan.sumber
cut
). Itu juga tidak bergantung pada mengeksekusi perintah eksternal.Saya terkejut solusi bash murni ini tidak muncul:
Anda mungkin ingin mengatur ulang IFS ke nilai sebelumnya, atau
unset IFS
sesudahnya!sumber
IFS
parameter yang belum disetel dan posisional:IFS=_ read -r _ digs _ <<< "$a"; echo "$digs"
Membangun jawaban jor (yang tidak berhasil untuk saya):
sumber
cut
.Mengikuti persyaratan
Saya menemukan beberapa
grep
cara yang mungkin berguna:atau lebih baik
Dan kemudian dengan
-Po
sintaks:Atau jika Anda ingin membuatnya pas dengan 5 karakter:
Akhirnya, untuk membuatnya disimpan dalam variabel itu hanya perlu menggunakan
var=$(command)
sintaks.sumber
Invocation as 'egrep' is deprecated; use 'grep -E' instead
. Saya sudah mengedit jawaban Anda.Jika kita fokus pada konsep:
"Jumlah (satu atau beberapa) digit"
Kita bisa menggunakan beberapa alat eksternal untuk mengekstraksi angka.
Kami dapat dengan mudah menghapus semua karakter lain, baik sed atau tr:
Tetapi jika $ name berisi beberapa proses angka, hal di atas akan gagal:
Jika "name = someletters_12345_moreleters_323_end.ext", maka:
Kita perlu menggunakan expresi reguler (regex).
Untuk memilih hanya menjalankan pertama (12345 bukan 323) di sed dan perl:
Tapi kita bisa melakukannya langsung di bash (1) :
Ini memungkinkan kita untuk mengekstrak deretan angka pertama dengan panjang berapa pun yang
dikelilingi oleh teks / karakter lain.
Catatan :
regex=[^0-9]*([0-9]{5,5}).*$;
hanya akan cocok dengan berjalan 5 digit. :-)(1) : lebih cepat daripada memanggil alat eksternal untuk setiap teks pendek. Tidak lebih cepat daripada melakukan semua pemrosesan dalam sed atau awk untuk file besar.
sumber
Tanpa sub-proses, Anda dapat:
Varian yang sangat kecil ini juga akan berfungsi di ksh93.
sumber
Berikut solusi akhiran-akhiran (mirip dengan solusi yang diberikan oleh JB dan Darron) yang cocok dengan blok angka pertama dan tidak bergantung pada garis bawah di sekitarnya:
sumber
Saya suka
sed
kemampuan untuk berurusan dengan grup regex:Sebuah pilihan yang sedikit lebih umum akan tidak berasumsi bahwa Anda memiliki garis bawah
_
untuk menandai dimulainya urutan angka Anda, maka misalnya menanggalkan semua non-nomor yang Anda dapatkan sebelum urutan Anda:s/[^0-9]\+\([0-9]\+\).*/\1/p
.Lebih lanjut tentang ini, jika Anda tidak terlalu percaya diri dengan regexps:
s
adalah untuk _s_ubstitute[0-9]+
cocok dengan 1+ digit\1
tautan ke grup n.1 dari output regex (grup 0 adalah seluruh kecocokan, grup 1 adalah kecocokan dalam kurung dalam kasus ini)p
bendera untuk _p_rintingSemua lolos
\
ada untuk membuatsed
pekerjaan pemrosesan regexp.sumber
Jawaban saya akan memiliki kontrol lebih besar pada apa yang Anda inginkan dari string Anda. Berikut adalah kode tentang cara mengekstrak
12345
string AndaIni akan lebih efisien jika Anda ingin mengekstraksi sesuatu yang memiliki karakter suka
abc
atau karakter khusus seperti_
atau-
. Misalnya: Jika string Anda seperti ini dan Anda menginginkan semua yang ada setelahsomeletters_
dan sebelumnya_moreleters.ext
:Dengan kode saya, Anda dapat menyebutkan apa yang sebenarnya Anda inginkan. Penjelasan:
#*
Ini akan menghapus string sebelumnya termasuk kunci yang cocok. Di sini kunci yang kami sebutkan adalah_
%
Ini akan menghapus string berikut termasuk kunci yang cocok. Di sini kunci yang kami sebutkan adalah '_more *'Lakukan beberapa percobaan sendiri dan Anda akan menemukan ini menarik.
sumber
Test.txt yang diberikan adalah file yang berisi "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
sumber
Ok, ini dia Substitusi Parameter murni dengan string kosong. Peringatan adalah bahwa saya telah mendefinisikan someletters dan moreletters hanya sebagai karakter. Jika mereka alfanumerik, ini tidak akan berfungsi sebagaimana mestinya.
sumber
mirip dengan substr ('abcdefg', 2-1, 3) di php:
sumber
Ada juga perintah bash builtin 'expr':
sumber
expr
bukan builtin.=~
operator yang didukung oleh[[
.Sedikit terlambat, tetapi saya hanya menemukan masalah ini dan menemukan yang berikut:
Saya menggunakannya untuk mendapatkan resolusi milidetik pada sistem tertanam yang tidak memiliki% N untuk tanggal:
sumber
Solusi bash:
Ini akan mengalahkan variabel yang dipanggil
x
. Varx
bisa diubah menjadi var_
.sumber
Akhir inklusif, mirip dengan implementasi JS dan Java. Hapus +1 jika Anda tidak menginginkan ini.
Contoh:
Lebih banyak contoh panggilan:
Sama sama.
sumber