bash: cara meneruskan argumen baris perintah yang berisi karakter khusus

31

Saya telah menulis sendiri program linux programyang membutuhkan ekspresi reguler sebagai input.

Saya ingin memanggil program di bashshell dan meneruskan ekspresi reguler sebagai argumen baris perintah ke program (ada juga argumen baris perintah lainnya). Seperti biasa, ekspresi reguler

[abc]\_[x|y]

Sayangnya karakter [, ]dan |karakter khusus di bash. Demikian panggilan

program [abc]\_[x|y] anotheragument

tidak bekerja Apakah ada cara untuk melewatkan ekspresi dengan menggunakan semacam karakter pelarian atau tanda kutip dll?

(Memanggil program "[abc]\_[x|y] anotheragument"tidak berfungsi juga, karena menafsirkan kedua argumen sebagai satu.)

Kristen
sumber

Jawaban:

27

Anda juga bisa

  1. Lepaskan setiap simbol khusus dengan garis miring terbalik (seperti dalam \[abc\]_\[x\|y\]) atau
  2. Buat tanda kutip seluruh argumen (seperti dalam "[abc]_[x|y]").

EDIT: Seperti yang telah ditunjukkan beberapa orang , dobleqouting tidak mencegah ekspansi variabel atau substitusi perintah. Karenanya jika regex Anda berisi sesuatu yang dapat diartikan oleh bash sebagai salah satunya, gunakan tanda kutip tunggal sebagai gantinya.

antikris
sumber
4
Dalam bash, kutip ganda tidak mem - bypass variabel "$HOME"atau parameter yang berkembang "${USER:-root}", substitusi perintah dalam bentuk apa pun , "$(date)"atau "`date`"ekspansi aritmatika "$((1 + 2))", ekspansi sejarah, "!!"atau pelarian backslash "\\". Gunakan tanda kutip tunggal sebagai gantinya. Lihat halaman manual manual bash, bagian berjudul "Mengutip".
Flimm
25

Gunakan tanda kutip tunggal. Kutipan tunggal memastikan bahwa tidak ada karakter yang ditafsirkan.

$ printf %s 'spaces  are  not  interpreted away
neither are new lines
nor variable names $TESTING
nor square brackets [TESTING]
nor pipe characters or redirection symbols | > <
nor the semicolon ;
nor backslashes \a \b \c \\
the only thing that does not work is the single quote itself
'

Ada dua solusi jika Anda perlu menyematkan satu kutipan:

$ printf '%s\n' '[ Don'"'"'t worry, be happy! ]'
[ Don't worry, be happy! ]
$ printf '%s\n' '[ Don'\''t worry, be happy! ]'
[ Don't worry, be happy! ]
Flimm
sumber
Kamu benar. +1
antikris
6

Per man bash

Ada tiga mekanisme penawaran: karakter melarikan diri , kutipan tunggal, dan kutipan ganda.

Garis miring terbalik ( \ ) adalah karakter pelarian . Ini mempertahankan nilai literal dari karakter berikutnya yang mengikuti, dengan pengecualian <newline>. Jika pasangan \ <newline> muncul, dan garis miring terbalik tidak dikutip sendiri, \ <newline> diperlakukan sebagai kelanjutan garis (yaitu, ia dihapus dari aliran input dan diabaikan secara efektif).

Menutup karakter dalam tanda kutip tunggal mempertahankan nilai literal setiap karakter dalam tanda kutip. Kutipan tunggal mungkin tidak terjadi di antara tanda kutip tunggal, bahkan ketika didahului oleh garis miring terbalik.

Melampirkan karakter dalam tanda kutip ganda mempertahankan nilai literal dari semua karakter dalam tanda kutip, dengan pengecualian $ , ` , \ , dan, ketika ekspansi sejarah diaktifkan, ! . Karakter $ dan ` mempertahankan makna khusus mereka dalam tanda kutip ganda. Garis miring terbalik hanya memiliki makna khusus ketika diikuti oleh salah satu karakter berikut: $ , ` , " , \ , atau <newline> . Kutipan ganda dapat dikutip dalam tanda kutip ganda dengan mendahului dengan garis miring terbalik. Jika diaktifkan, ekspansi sejarah akan dilakukan kecuali! muncul dalam tanda kutip ganda diloloskan menggunakan backslash. Garis miring terbalik sebelum ! tidak dihapus.

Parameter khusus * dan @ memiliki arti khusus ketika dalam tanda kutip ganda (lihat PARAMETER di bawah).

Kata-kata dalam bentuk $ ' string ' diperlakukan secara khusus. Kata diperluas ke string , dengan karakter backslash-escaped diganti sebagaimana ditentukan oleh standar ANSI C. Urutan melarikan diri backslash, jika ada, diterjemahkan sebagai berikut:

       \ a      alert (bell)
        \ b      backspace
        \ e 
       \ E      karakter pelarian
        \ f      form feed
        \ n      baris baru
        \ r      carriage return
        \ t      tab horizontal
        \ v      tab vertikal
        \      backslash
        \ '      single quote
        \ "      double quote
        \ nnn    the karakter delapan bit yang nilainya adalah nilai oktal nnn
              (satu hingga tiga digit)
       \ x HH    karakter delapan-bit yang nilainya adalah nilai heksadesimal HH
              (satu atau dua digit hex)
       \ u HHHH karakter Unicode (ISO / IEC 10646) yang nilainya
              nilai heksadesimal HHHH (satu hingga empat digit hex)
        \ U HHHHHHHH
              karakter Unicode (ISO / IEC 10646) yang nilainya
              nilai heksadesimal HHHHHHHH (1-8 hex digit)
        \ c x     sebuah kontrol- x karakter

Hasil diperluas dikutip tunggal, seolah-olah tanda dolar tidak ada.

String yang dikutip ganda didahului oleh tanda dolar ( $ " string " ) akan menyebabkan string diterjemahkan sesuai dengan lokal saat ini. Jika lokal saat ini adalah C atau POSIX , tanda dolar diabaikan. Jika string diterjemahkan dan diganti, penggantiannya dikutip ganda.

Evan Carroll
sumber
2

Anda dapat menggunakan garis miring terbalik ( \) di depan karakter khusus untuk menghindarinya seperti:

john @ mengagumkan: ~ # echo \ &
&
John T
sumber
2

Meskipun mungkin tidak berguna sebagai regex, beberapa urutan karakter dapat ditafsirkan sebagai nama variabel Bash. Untuk mencegah hal ini terjadi dan menghindarinya, gunakan tanda kutip tunggal alih-alih tanda kutip ganda:

program '[abc]_[x|y]' anotherargument

Kutip setiap argumen secara terpisah (jika mereka perlu mengutip) sehingga mereka ditafsirkan sebagai argumen independen. Anda juga dapat menggunakan array dalam beberapa kasus:

param_array=('[abc]_[x|y]' anotherargument)    # create an array
param_array+=(yetanother)     # append another element to the array
program "${param_array[@]}"   # use the array elements as arguments to program
Dijeda sampai pemberitahuan lebih lanjut.
sumber
1
program "[abc]_[x|y]"
program "[abc]_[x|y]" anotherargument
Witek
sumber
0

Melarikan diri dari mereka harus bekerja dengan baik:

  programm \[abc\]_\[x\|y\]
Polisi
sumber
0

Dari mana pola itu berasal? Apakah sudah diperbaiki atau dari pengguna? Apakah pengguna yang menggunakan skrip pada sistem lokal, atau seseorang yang jauh?

Anda menggunakan kutipan untuk membungkus data agar shell tidak menafsirkannya. Ada dua opsi:

  1. Kutipan ganda, yang masih mengizinkan beberapa interpretasi ($ perluas dan `backticks`)
  2. Kutipan tunggal, yang melewati segalanya secara harfiah

Karena $karakter yang valid di regexps (end-of-line / buffer) Anda mungkin ingin menggunakan tanda kutip tunggal untuk menahan regexp, kecuali Anda menyimpannya dalam variabel. Jika Anda mengambil data sewenang-wenang dari seseorang yang tidak dipercaya, Anda harus menggantinya 'dengan '"'"'dan kemudian membungkusnya dengan tanda kutip tunggal.

Catatan yang [abc]_[x|y]sepertinya Anda ingin cocokkan xatau y, sementara itu sebenarnya cocok dengan salah satu dari tiga karakter xy|. Kurung kotak cocok dengan karakter di dalam dan hanya -untuk rentang dan ^di awal untuk negasi. Jadi, [abc]_(x|y)mungkin itu yang Anda maksud, dan tanda kurung adalah karakter yang khusus untuk shell. Kurung kotak tidak khusus untuk di-shell, sepertinya begitu. Tanda kurung ganda [[ ... ]]adalah spesial.

Phil P
sumber
Ini adalah salah satu jawaban yang paling benar di sini (saya menghargai terutama instruksi untuk mengganti 'dengan '"'"'), namun, masih tidak benar. [ADALAH karakter khusus untuk shell, digunakan dalam wildcard ketika melakukan path-expansion (shell tidak untuk semua tanda kutip).
jpalecek
Ini khusus dalam beberapa konteks, seperti subskrip variabel atau untuk globbing, tetapi Anda masih bisa mengetik foo=a[b]dan kemudian echo $foodan melihat bahwa string tidak perlu mengutip. Anda benar, saya terlalu singkat.
Phil P
Jika Anda beruntung, ada file abdi direktori saat ini, dan kemudian fooakan berisi abdaripada a[b]. Kutip kurung kotak Anda, orang-orang.
clacke
(Untuk kejelasan: Saya mengutip (seperti jawaban asli dibuat jelas, di mana saya mendorong untuk mengutip), dan ini adalah penggelinciran samping yang saya bahas). Pernyataan ini mengejutkan saya, jadi saya mengujinya. Itu tidak benar di zsh atau bash, tetapi benar di BSD / bin / sh. Ini bertentangan dengan POSIX dan merupakan perilaku non-standar, jadi Anda perlu mengutip untuk menanganinya. Di zsh, Anda dapat setopt glob_assignmengaktifkan perilaku ini juga, jadi mengutip adalah jawaban yang paling aman.
Phil P