Ada banyak cara untuk mengganti karakter dalam suatu variabel.
Cara terpendek yang saya temukan tr
sejauh ini:
OUTPUT=a\'b\"c\`d_123and_a_lot_more
OUTPUT=$(echo "$OUTPUT"|tr -d "'\`\"")
echo $OUTPUT
Apakah ada cara yang lebih cepat? Dan apakah kutipan ini aman untuk kutipan seperti '
, "
dan `sendiri?
tr
. BASH's PE bagus tetapi tr jauh lebih cepat dalam kasus ini. mis.echo "$OUTPUT" | tr -dc '[[:alpha:]]'
karena Anda hanya ingin memiliki alfanumerikecho "$OUTPUT"
. Atau lebih baik:printf "%s\n" "$OUTPUT"
. (Apa yang terjadi kapanOUTPUT="-n"
?)Jawaban:
Ayo lihat. Yang terpendek yang bisa saya kemukakan adalah tweak dari
tr
solusi Anda :Alternatif lain termasuk substitusi variabel yang sudah disebutkan yang bisa lebih pendek dari yang ditunjukkan sejauh ini:
Dan
sed
tentu saja meskipun ini lebih panjang dalam hal karakter:Saya tidak yakin apakah maksud Anda pendek atau dalam waktu yang singkat. Dalam hal panjang, keduanya pendek seperti yang didapat (atau seperti yang bisa saya dapatkan) ketika harus menghapus karakter tertentu. Jadi, mana yang tercepat? Saya menguji dengan menetapkan
OUTPUT
variabel ke apa yang Anda miliki dalam contoh Anda tetapi diulang beberapa lusin kali:Seperti yang Anda lihat,
tr
ini jelas yang tercepat, diikuti olehsed
. Juga, sepertinya menggunakanecho
sebenarnya sedikit lebih cepat daripada menggunakan<<<
:Karena perbedaannya kecil, saya menjalankan tes di atas 10 kali untuk masing-masing dari keduanya dan ternyata yang tercepat memang yang Anda harus mulai dengan:
Namun, ini berubah ketika Anda memperhitungkan overhead penetapan ke variabel, di sini, menggunakan
tr
sedikit lebih lambat daripada penggantian sederhana:Jadi, sebagai kesimpulan, ketika Anda hanya ingin melihat hasilnya, gunakan
tr
tetapi jika Anda ingin menetapkan kembali ke variabel, menggunakan fitur manipulasi string shell lebih cepat karena mereka menghindari overhead menjalankan subkulit terpisah.sumber
OUTPUT
, Anda harus memperhitungkan penggantian overhead sub-shell substitusi perintah yang terlibattr
dansed
solusinyaOUTPUT="${OUTPUT//[`\"\']/}"
tidak melibatkan penggantian perintahAnda bisa menggunakan substitusi variabel :
Gunakan sintaksis itu:
${parameter//pattern/string}
untuk mengganti semua kemunculan pola dengan string.sumber
echo ${OUTPUT//[`\"\']/x}
memberiaxbxcxa
Dalam bash atau zsh itu adalah:
Perhatikan bahwa
${VAR//PATTERN/}
menghapus semua instance dari pola. Untuk informasi lebih lanjut, ekspansi parameter bashSolusi ini harus tercepat untuk string pendek karena tidak melibatkan menjalankan program eksternal apa pun. Namun untuk string yang sangat panjang kebalikannya benar - lebih baik menggunakan alat khusus untuk operasi teks, misalnya:
sumber
tr
lebih cepat. Regex dan gumpalan mahal, dan sementara tidak ada program eksternal di sini, bash akan selalu lebih lambat daripada sesuatu sepertitr
.tr
menang (lihat jawaban saya). Saya setuju bahwa itu akan tergantung pada banyak faktor tetapi itulah mengapa Anda tidak dapat menentukan mana yang menang tanpa benar-benar mengujinya.Jika, jika tidak sengaja, Anda hanya mencoba menangani tanda kutip untuk menggunakan kembali shell, maka Anda dapat melakukan ini tanpa menghapusnya, dan itu juga sederhana:
Shell fungsi itu mengutip setiap argumen arg yang Anda berikan dan meningkatkan outputnya per argumen yang dapat diperbaiki.
Ini dia dengan beberapa argumen:
KELUARAN
Keluaran itu dari
dash
mana biasanya kutipan dengan kutip tunggal berupa keluaran yang disukai'"'"'
.bash
akan lakukan'\''
.Mengganti pilihan byte tunggal, non-spasi putih, non-nol dengan byte tunggal lainnya mungkin dapat dilakukan paling cepat di setiap shell POSIX dengan
$IFS
dan$*
.KELUARAN
Di sana saya hanya
printf
agar Anda dapat melihatnya, tetapi tentu saja, jika saya telah melakukannya:... daripada
printf
perintah$var
akan menjadi apa yang Anda lihat di output di sana.Ketika saya
set -f
memerintahkan shell untuk tidak glob - jika string berisi karakter yang dapat ditafsirkan sebagai pola glob. Saya melakukan ini karena parser shell memperluas pola glob setelah melakukan pemisahan bidang pada variabel. globbing dapat diaktifkan kembali sepertiset +f
. Secara umum - dalam skrip - saya merasa berguna untuk mengatur bang saya seperti:Dan kemudian secara eksplisit mengaktifkan globbing dengan
set +f
apa pun garis yang saya inginkan.Pemecahan bidang terjadi berdasarkan karakter dalam
$IFS
.Ada dua jenis
$IFS
nilai -$IFS
spasi putih dan$IFS
non-spasi putih. bidang terbatas$IFS
spasi (spasi, tab, baris baru) ditetapkan untuk dihapus oleh urutan ke satu bidang (atau tidak sama sekali jika tidak mendahului hal lain) - jadi ...Tetapi semua yang lain ditentukan untuk mengevaluasi ke satu bidang per kejadian - mereka tidak terpotong.
Semua ekspansi variabel, secara default,
$IFS
array data dibatasi - mereka dibagi ke bidang yang terpisah sesuai dengan$IFS
. Ketika Anda"
-quote satu Anda menimpa properti array itu dan mengevaluasinya sebagai string tunggal.Jadi ketika saya melakukannya ...
Saya mengatur array argumen shell ke banyak
$IFS
bidang terbatas yang dihasilkan oleh$var
ekspansi. Ketika diperluas nilai konstituen untuk karakter yang terkandung dalam$IFS
yang hilang - mereka hanya pemisah lapangan sekarang - mereka\0NUL
."$*"
- seperti ekspansi variabel ganda yang dikutip ganda - juga mengesampingkan kualitas pemisahan bidang dari$IFS
. Tetapi, di samping itu , ia menggantikan byte pertama$IFS
untuk setiap bidang yang dibatasi di"$@"
. Jadi karena"
merupakan pertama nilai dalam$IFS
semua pembatas berikutnya menjadi"
di"$*"
. Dan yang"
tidak perlu ada di$IFS
saat Anda membaginya, juga. Anda bisa mengubah$IFS
setelahset -- $args
ke nilai lain seluruhnya dan byte pertama yang baru kemudian akan muncul untuk pembatas bidang di"$*"
. Terlebih lagi, Anda dapat menghapus semua jejak mereka sepenuhnya seperti:KELUARAN
sumber
tr
di shell mana pun, tetapi perbedaannya rapuhbash
untuk${var//$c/$newc/}
kasus ini. Saya berharap bahkan dalam kasus itu akan lebih cepat dengan margin tertentu, tetapi saya biasanya tidak khawatir tentang itu karena untuk hal ini saya selalu menggunakandash
- yang lebih cepat dengan perintah besarnya pada umumnya dalam segala hal. Dan sulit untuk membandingkan.bash
melakukantime (IFS=\"\'`; set -- $var; printf %s "$*")
dantime (var=${var//\'`/\"/})
keduanya menghasilkan0.0000s
hasil untuk semua bidang. Apakah saya melakukan sesuatu yang salah, menurut Anda? Seharusnya ada backslash sebelum backquote di sana, tetapi saya tidak tahu bagaimana menempatkan backquote di bidang kode komentar.