Bagaimana cara melepaskan karakter khusus dalam sebuah string?


16

Dengan asumsi $filememegang nilai nama file, katakanlah Dr' A.tif. Dalam pemrograman bash, bagaimana saya bisa lolos dari kutipan tunggal dan karakter khusus lainnya $filetanpa menghilangkan karakter khusus?

Pembaruan pada 9 Juli 2014

Sebagai permintaan dari @Gilles , cuplikan kode berikut ini yang tidak dapat menangani Dr' A.tif:

files=$(find /path/ -maxdepth 1 -name "*.[Pp][Dd][Ff]" -o -name "*.[Tt][Ii][Ff]")
echo "${files}" > ${TEMP_FILE}
while read file
do
   newfile=$(echo "${file}" | sed 's, ,\\ ,g') ## line 1
done < ${TEMP_FILE}

Setelah saya mencoba jawaban dari @Patrick pada line 1, sepertinya berhasil untuk saya. Tetapi jika saya memiliki file seperti itu Dr\^s A.tif, printfperintah sepertinya tidak membantu, itu menunjukkan kepada saya Dr\^s\ A.tif. Jika saya mencobanya secara manual di konsol seperti ini:

printf "%q" "Dr\^s A.tif"

Saya akan mendapatkan hasil ini:

Dr\\\^s\ A.tif

Adakah cara menangani ini?


3
dalam konteks apa Anda mengharapkan untuk menggunakan $ file? atau apakah masalah ini menetapkan string dengan karakter khusus ke $ file?
merampok

Sebenarnya perintah find mengembalikan saya daftar file. Dan kemudian saya loop melalui daftar file ini menjadi variabel $ file.
huahsin68

2
Anda telah diberikan beberapa jawaban yang benar di sini, tetapi mereka mungkin bukan jawaban untuk pertanyaan yang benar-benar Anda tanyakan. Dari komentar Anda di sini, saya sangat curiga bahwa Anda berada di jalur yang salah. Kami tidak dapat banyak membantu Anda karena Anda tetap tidak menunjukkan kode Anda. Namun saya menyarankan Anda membaca Mengapa skrip shell saya tersedak di spasi putih atau karakter khusus lainnya? sebagai latar belakang. Perlihatkan skrip Anda dan jelaskan apa yang ingin Anda lakukan.
Gilles 'SANGAT berhenti menjadi jahat'

Jawaban:


14

Anda dapat menggunakan printfbuiltin dengan %quntuk mencapai ini. Sebagai contoh:

$ file="Dr' A.tif"
$ printf '%q\n' "$file"
Dr\'\ A.tif

$ file=' foo$bar\baz`'
$ printf '%q\n' "$file"
\ foo\$bar\\baz\`

Dari dokumentasi bash tentang printf:

In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:

 %b       expand backslash escape sequences in the corresponding argument
 %q       quote the argument in a way that can be reused as shell input
 %(fmt)T  output the date-time string resulting from using FMT as a format
          string for strftime(3)

Ini tidak bekerja dengan kasus tertentu. Misalnya ketika Anda perlu mempertahankan tanda kutip ganda.
user3467349

@ user3467349 berfungsi dengan baik dengan tanda kutip. Saya yakin Anda sedang mencoba sesuatu printf '%s' "foo". Anda perlu memahami cara kerja parsing argumen di shell terlebih dahulu. Lihat gnu.org/software/bash/manual/bash.html#Shell-Operation # 2 terjadi sebelum # 6.
Patrick

Bisakah Anda memberikan contoh string ini yang dicetak dengan printfdan tanpa manipulasi lainIt doesn't have a: ""
user3467349

Masalah Anda tidak ada hubungannya dengan printf. Masalah Anda adalah Anda tidak ingin shell menguraikan string Anda. Untuk melakukan itu, Anda harus meneruskan input Anda ke shell dengan cara di mana ia bahkan tidak mencoba untuk menguraikannya. Salah satu cara untuk melakukan ini adalah read -r -p 'input: ' && printf '%q\n' "$REPLY", dan memberikan input saat diminta.
Patrick

1
Seperti yang saya katakan beberapa kali sekarang. Tidak tahu bagaimana cara mengirimkan data mentah ke shell tidak menjadi masalah printf. Mungkin Anda harus mengajukan pertanyaan daripada mengkritik solusi yang tidak ada hubungannya dengan masalah Anda.
Patrick

4

Mencoba:-

file=Dr\'\ A.tif
echo $file
Dr' A.tif

atau

file="Dr' A.tif"
echo $file
Dr' A.tif

atau jika string berisi kutipan ganda: -

file='Dr" A.tif'
echo $file
Dr" A.tif

Ada tutorial bagus tentang cara melarikan diri dan mengutip di internet. Mulailah dengan yang ini .


1

Anda tidak perlu keluar dari nama file apa pun yang Anda tangani dalam skrip. Melarikan diri hanya diperlukan jika Anda ingin meletakkan nama file sebagai literal dalam skrip, atau untuk memberikan beberapa nama file sebagai input stream tunggal ke skrip lain.

Karena Anda mengulang-ulang keluaran find, ini adalah salah satu cara paling sederhana (!) Untuk menangani setiap jalur yang mungkin :

while IFS= read -r -d ''
do
    file_namex="$(basename -- "$REPLY"; echo x)"
    file_name="${file_namex%$'\nx'}"
    do_something -- "$file_name"
done <(find "$some_path" -exec printf '%s\0' {} +)

0

cepat dan (sangat) kotor

find . | sed 's/^/"/' | sed 's/$/"/'

-1

Banyak jawaban ini termasuk yang menggunakan suara terbanyak menggunakan printf "%q"tidak akan berfungsi dalam semua kasus tanpa manipulasi tambahan. Saya akan menyarankan yang berikut (contoh di bawah):

cat <<EOF; 2015-11-07T03:34:41Z app[postgres.0000]: [TAG] text-search query doesn't contain lexemes: "" EOF


Maafkan pertanyaan n00b tetapi dapatkah Anda menguraikan bagaimana sebenarnya Anda akan menggunakan ini untuk melarikan diri karakter dalam string? Jika saya menyalin kode yang Anda tulis ke terminal saya, ia hanya mencetak 2015-11-07T03: 34: 41Z aplikasi [postgres.0000]: [TAG] permintaan pencarian teks tidak mengandung leksem: "" ... tidak ada yang lolos .
SharkAlley

Yang secara harfiah titik, semua karakter khusus yang ditafsirkan sebagai karakter literal bukan untuk arti khusus mereka. Cobalah gema "string di atas" sebagai gantinya untuk melihat perbedaannya.
user3467349
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.