Cara lolos dari satu kutipan di dalam awk

111

Saya ingin melakukan hal berikut

awk 'BEGIN {FS=" ";} {printf "'%s' ", $1}'

Tapi melarikan diri dari kutipan tunggal dengan cara ini tidak berhasil

awk 'BEGIN {FS=" ";} {printf "\'%s\' ", $1}'

Bagaimana cara melakukannya? Terimakasih atas bantuannya.

codeforester
sumber
Sejumlah bahasa menghindari kutipan dengan meletakkan dua di antaranya berturut-turut, mungkin coba itu.
joshuahealy
Saya mencoba awk 'BEGIN {FS = "";} {printf "' '% s' '", $ 1}', tetapi tidak ada kutipan tunggal yang dicetak.
Halaman ini mengatakan bahwa menyertakan satu kutipan dalam string kutipan tunggal tidak mungkin. Mungkin Anda harus mengubahnya menjadi tanda kutip ganda.
joshuahealy
2
Hal ini tidak mungkin, tetapi dua string shell bertanda kutip tunggal yang berdekatan menempel menjadi satu parameter. Dan dua string shell bertanda kutip tunggal yang direkatkan oleh karakter non-spasi juga menempel menjadi satu bola besar: 'abc'd'ef'is abcdef: literal plus dplus literal. Itu di dluar tanda kutip, dan Anda dapat menggantinya ddengan \'membuat 'abc'\''ef'yang mengevaluasi ke abc'ef.
Kaz

Jawaban:

160

Ini mungkin yang Anda cari:

awk 'BEGIN {FS=" ";} {printf "'\''%s'\'' ", $1}'

Artinya, dengan '\''Anda menutup bukaan ', lalu cetak literal 'dengan meloloskan diri dari itu dan akhirnya buka 'lagi.

Steve
sumber
48
Ini tidak ada hubungannya dengan awk. The 'karakter menutup pembukaan 'literal shell tali. Literal shell tidak mendukung pelolosan garis miring terbalik untuk ini. Urutan '\''melakukan trik: menutup single-quote literal, menspesifikasikan karakter quote (menggunakan pelarian yang adalah didukung di luar literal single-quote) dan kemudian kembali membuka sebuah single baru-kutipan literal. Anda dapat menganggapnya sebagai urutan pelolosan empat karakter untuk mendapatkan satu kutipan. :)
Kaz
2
@ Steve: Terima kasih banyak atas jawaban Anda yang sangat berguna. Anda menyelamatkan saya dari banyak sakit kepala!
John Slegers
4
@syntaxerror Kutipan apa yang Anda gunakan untuk menyiapkan argumen untuk pemanggilan awkadalah murni masalah penerjemah perintah yang Anda gunakan untuk membuat baris perintah. Itu '{printf $2}'akan berubah menjadi beberapa argumen untuk execvepanggilan sistem atau serupa, di mana itu hanya terlihat seperti string C yang diakhiri null tanpa tanda kutip tunggal. Awk tidak pernah melihat kutipannya, begitu pula sed. Anda dapat sebenarnya penggunaan tanda kutip ganda, tapi tanda kutip ganda tidak mencegah ekspansi shell dari $2, sehingga Anda harus melarikan diri tanda dolar dengan garis miring terbalik untuk membuatnya literal: "{printf \$2}".
Kaz
4
@syntaxerror Secara khusus, skrip awk sebaris biasanya diloloskan dengan tanda kutip tunggal, karena sintaks awk sering kali berisi elemen leksikal yang khusus untuk shell, seperti literal string yang dikutip ganda, dan bidang bernomor yang dilambangkan dengan tanda dolar. Jika ekspresi reguler sed (atau apa pun) berisi sintaks shell, Anda juga harus berhati-hati. sed -e "s/$FOO/$BAR/"tidak akan berfungsi jika tujuannya adalah untuk mengganti teks literal $FOOdengan $BAR. Cara termudah adalah sed -e 's/$FOO/$BAR/.
Kaz
1
@syntaxerror Jika Anda menyertakan program awk dalam tanda kutip ganda, Anda akan mengalami banyak pelolosan, seperti awk "{ print \"abc\", \$1 }". Setiap kali tanda kutip ganda muncul di program awk, itu harus di-escape agar tidak menutup kutipan shell. Dan bandingkan ini: awk '{print "\\"}'(cetak garis miring terbalik) versus apa yang diperlukan dengan tanda kutip ganda awk "BEGIN {print \"\\\\\" }":, Fiuh! Kedua tanda kutip harus di-escape, dan keduanya memiliki garis miring terbalik. Shell diubah \\ menjadi \ jadi kita perlu \\\\ melakukan encode \\ .
Kaz
76

Kutipan tunggal diwakili menggunakan \x27

Seperti di

awk 'BEGIN {FS=" ";} {printf "\x27%s\x27 ", $1}'

Sumber

tiagojco
sumber
16
+1, tetapi perlu menambahkan: \x27adalah ekstensi; POSIX Awk hanya mengenali \047. ( \47tidak apa-apa juga jika tidak diikuti dengan digit oktal.)
hemflit
1
Bagaimana Anda mengakhiri \ x27 jika Anda memiliki nomor lain setelahnya?
Jason Axelson
1
Jason, Anda menggabungkan dua string literal: "AAA \ x27" "1". Atau Anda hanya menggunakan oktal.
hemflit
9
Selalu gunakan octal ( \047), bukan hex ( \x27), kode escape - lihat awk.freeshell.org/PrintASingleQuote .
Ed Morton
35

Opsi lainnya adalah meneruskan kutipan tunggal sebagai variabel awk :

awk -v q=\' 'BEGIN {FS=" ";} {printf "%s%s%s ", q, $1, q}'

Contoh yang lebih sederhana dengan penggabungan string:

# Prints 'test me', *including* the single quotes.
$ awk -v q=\' '{print q $0 q }' <<<'test me'
'test me'
mklement0
sumber
5
Ini jelas dan ringkas, terutama jika Anda perlu menggunakan banyak kutipan.
Peter Gluck
18
awk 'BEGIN {FS=" "} {printf "\047%s\047 ", $1}'
Sergio K
sumber
1
Selama saya ingat itu \047adalah urutan pelarian oktal untuk karakter tanda kutip tunggal, saya menemukan alternatif ini yang paling mudah dibaca.
Anthony Geoghegan
4

Untuk skrip kecil, cara opsional agar dapat dibaca adalah dengan menggunakan variabel seperti ini:

awk -v fmt="'%s'\n" '{printf fmt, $1}'

Saya menemukan itu mudah dalam kasus di mana saya harus menghasilkan berkali-kali karakter tanda kutip tunggal dalam output dan \ 047 membuatnya benar-benar tidak dapat dibaca

pengguna1708042
sumber