Script Shell - hapus kutipan pertama dan terakhir (") dari variabel

225

Di bawah ini adalah potongan skrip shell dari skrip yang lebih besar. Ini menghapus tanda kutip dari string yang dipegang oleh variabel. Saya melakukannya dengan menggunakan sed, tetapi apakah ini efisien? Jika tidak, lalu apa cara yang efisien?

#!/bin/sh

opt="\"html\\test\\\""
temp=`echo $opt | sed 's/.\(.*\)/\1/' | sed 's/\(.*\)./\1/'`
echo $temp
pengguna1263746
sumber
Saya sarankan menggunakan sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt". Sintaks ini hanya akan menghapus qoutes ketika ada pasangan yang cocok.
John Smith
@ JohnSmith Saya juga harus secara otomatis menghindari tanda kutip dalam skrip shell, tetapi saya harus melakukannya apakah mereka cocok atau tidak, jadi saya mungkin tidak akan menggunakan ungkapan yang Anda pasang.
Pysis
Jika Anda menemukan pertanyaan ini sambil hanya ingin menghapus semua kutipan, lihat jawaban ini: askubuntu.com/a/979964/103498 .
Gordon Bean

Jawaban:

268

Ada cara yang lebih sederhana dan lebih efisien, menggunakan fitur prefix / suffix shell asli:

temp="${opt%\"}"
temp="${temp#\"}"
echo "$temp"

${opt%\"}akan menghapus suffix "(lolos dengan backslash untuk mencegah interpretasi shell).

${temp#\"}akan menghapus awalan "(lolos dengan backslash untuk mencegah interpretasi shell).

Keuntungan lain adalah bahwa ia akan menghapus tanda kutip sekitarnya hanya jika ada tanda kutip sekitarnya.

BTW, solusi Anda selalu menghilangkan karakter pertama dan terakhir, apa pun itu (tentu saja, saya yakin Anda tahu data Anda, tetapi selalu lebih baik untuk memastikan apa yang Anda hapus).

Menggunakan sed:

echo "$opt" | sed -e 's/^"//' -e 's/"$//'

(Versi yang ditingkatkan, seperti yang ditunjukkan oleh jfgagne, menyingkirkan gema)

sed -e 's/^"//' -e 's/"$//' <<<"$opt"

Jadi itu menggantikan yang memimpin "dengan yang tidak ada, dan yang tertinggal "dengan yang juga. Dalam doa yang sama (tidak perlu melakukan pipa dan memulai sed lain. Menggunakan -eAnda dapat memiliki beberapa pemrosesan teks).

huelbois
sumber
14
Anda dapat menyingkirkan pipa dengan solusi sed sed -e 's/^"//' -e 's/"$//' <<< $opt.
jfg956
1
Ini bisa keliru jika string tidak memiliki karakter kutipan terkemuka dan tertinggal. Adakah saran untuk menanganinya dengan anggun?
jsears
Untuk menangani hanya kutipan luar yang cocok, lihat jawaban oleh @ Joachim Pileborg
jsears
1
@ jsears Huh? Ini secara khusus memotong satu dari awal jika ada, dan satu dari ujung jika ada. Jika Anda tidak ingin menghapus kecuali keduanya ada; ya, satu sedregex dapat digunakan, atau substitusi variabel dapat dibungkus dalam garis sesuatucase $opt in '"'*'"') ... do it ... ;; esac
tripleee
2
Anda dapat menghindari beberapa ekspresi dengan menggunakansed 's/^"\|"$//g'
tzrlk
287

Gunakan tr untuk menghapus ":

 echo "$opt" | tr -d '"'

Catatan : Ini menghapus semua tanda kutip ganda, tidak hanya mengarah dan mengekor.

wieczorek1990
sumber
16
Ini bukan yang diminta OP karena ia juga menghilangkan semua kuotasi, bukan hanya yang terkemuka dan yang tertinggal.
Lenar Hoyt
19
Meskipun tidak menjawab OP secara eksplisit, ini diselesaikan untuk saya karena hanya ada tanda kutip ganda pada awal dan akhir "/ path / nama file". Tidak ada tanda kutip ganda tertanam. +1
WinEunuuchs2Unix
6
Solusi ini akan menjadi apa yang diinginkan banyak orang. Dalam banyak kasus, skrip dapat dengan mudah mendapatkan data yang bisa diterapkan ke string yang dikelilingi oleh tanda kutip.
Shadoninja
2
Elegan dan menyelamatkan saya dari lebih banyak waktu coba-coba-debug. Terima kasih.
Scott Wade
Inilah yang secara ideal diinginkan seseorang dan itulah mengapa ia memiliki lebih banyak suara daripada jawaban yang diterima.
apurvc
38

Ini akan menghapus semua tanda kutip ganda.

echo "${opt//\"}"
Steven Penny
sumber
1
Tetapi akan pecah dengan kutipan yang lolos, mis Don't remove this \" quote. , . :-(
gniourf_gniourf
Ini adalah ekstensi Bash, jadi tidak berlaku untuk skrip shell secara umum. (Pertanyaannya mendua apakah ini penting atau tidak. Pengunjung yang menemukan ini di Google mungkin mencari solusi POSIX.)
tripleee
Kesempurnaan! Apa yang saya butuhkan. Saya suka pertanyaan seperti ini yang memberi Anda banyak jawaban, bukan hanya apa yang diminta OP. Permata ada di jawaban yang tidak diterima!
dlite922
Saya khawatir OP ingin sesuatu yang hanya menghilangkan tanda kutip terkemuka / tertinggal dan membuat yang lolos.
Fernando Paz
36

Ada cara mudah menggunakan xargs :

> echo '"quoted"' | xargs
quoted

xargs menggunakan echo sebagai perintah default jika tidak ada perintah yang diberikan dan menghapus tanda kutip dari input. Lihat misalnya di sini .

pengguna1587520
sumber
echo '"quoted"' | xargs -> quoted
kyb
1
Ini berfungsi, tetapi hanya untuk sejumlah kutipan dalam sebuah string. Jika ada nomor ganjil, itu menghasilkan kesalahan.
James Shewey
21

Anda dapat melakukannya hanya dengan satu panggilan ke sed:

$ echo "\"html\\test\\\"" | sed 's/^"\(.*\)"$/\1/'
html\test\
Beberapa programmer Bung
sumber
19

Cara terpendek - coba:

echo $opt | sed "s/\"//g"

Ini benar-benar menghapus semua "s (tanda kutip ganda) dari opt(apakah benar-benar akan ada lebih banyak tanda kutip selain di awal dan akhirnya? Jadi itu sebenarnya hal yang sama, dan jauh lebih singkat ;-))

Dr.Kameleon
sumber
4
Jika Anda ingin menghapus semua tanda kutip ganda, maka itu lebih baik untuk menggunakan: "$ {opt // \" /} ". Tidak ada pipa, tidak ada subkulit ... Dan berhati-hatilah bahwa jika Anda memiliki spasi di pilih, Anda dapat kehilangan selalu kutip variabel seperti: echo "$ opt"
huelbois
Yah, variabel pada dasarnya membaca jalur DocumentRoot dari file konfigurasi httpd, jadi saya tidak berpikir ada kasus di mana karakter kutipan mungkin ada di string. Dan sed ini jauh lebih rapi dan efisien .... Terima kasih!
user1263746
16

Jika Anda menggunakan jq dan mencoba menghapus tanda kutip dari hasilnya, jawaban lain akan berfungsi, tetapi ada cara yang lebih baik. Dengan menggunakan -ropsi, Anda dapat menampilkan hasilnya tanpa tanda kutip.

$ echo '{"foo": "bar"}' | jq '.foo'
"bar"

$ echo '{"foo": "bar"}' | jq -r '.foo'
bar
membunuh kesenangan
sumber
Saya menggunakan jqtetapi harap dicatat bahwa itu tidak berfungsi jika jq juga mengeluarkan keluaran ASCII dengan -a(ini adalah bug di sisi jq)
Can Poyrazoğlu
yqjuga memiliki -ropsi:yq -r '.foo' file.yml
Hlib Babii
12

Memperbarui

Sebuah jawaban sederhana dan elegan dari Stripping tanda kutip tunggal dan ganda dalam string menggunakan perintah bash / standar Linux saja :

BAR=$(eval echo $BAR) strip kutipan dari BAR .

================================================== ===========

Berdasarkan jawaban hueybois, saya menemukan fungsi ini setelah banyak mencoba-coba:

function stripStartAndEndQuotes {
    cmd="temp=\${$1%\\\"}"
    eval echo $cmd
    temp="${temp#\"}"
    eval echo "$1=$temp"
}

Jika Anda tidak ingin apa pun dicetak, Anda dapat mengirimkan eval ke pipa /dev/null 2>&1 .

Pemakaian:

$ BAR="FOO BAR"
$ echo BAR
"FOO BAR"
$ stripStartAndEndQuotes "BAR"
$ echo BAR
FOO BAR
Jonathan Lin
sumber
1
Meskipun saya benar-benar menyukai yang sederhana dan elegan, saya pikir perlu memperhatikan bahwa eval tidak hanya melakukan dua kali pemotongan harga, tetapi sebenarnya mengevaluasi sebagai satu baris kode. Oleh karena itu teknik ini dapat menghasilkan hasil yang tidak terduga ketika BAR berisi urutan lain yang dapat menggantikan dengan shell (misalnya BAR = \ 'abc \' atau BAR = ab \ 'c atau BAR = a \ $ b, atau BAR = a \ $ (ls *))
Maks.
11

Solusi termudah di Bash:

$ s='"abc"'
$ echo $s
"abc"
$ echo "${s:1:-1}"
abc

Ini disebut perluasan substring (lihat Manual Gnu Bash dan cari ${parameter:offset:length}). Dalam contoh ini diperlukan substring dari smulai di posisi 1 dan berakhir di posisi terakhir kedua. Hal ini disebabkan oleh fakta bahwa jika lengthnilai negatif itu ditafsirkan sebagai offset berjalan mundur dari akhir parameter.

Hiro. Protagonis
sumber
panjang negatif didukung dari bash v4.2
mr.spuratic
8

Ini adalah cara yang paling berbeda tanpa menggunakan sed:

x='"fish"'
printf "   quotes: %s\nno quotes:  %s\n" "$x" "${x//\"/}"

Atau

echo $x
echo ${x//\"/}

Keluaran:

   quotes: "fish"
no quotes:  fish

Saya mendapat ini dari sumber .

nimig18
sumber
Ini akan menghapus tanda kutip dari dalam string dan juga orang-orang di sekitarnya.
jsears
Terlepas dari komentar, ini identik dengan jawaban @ StevenPenny dari 2012 .
tripleee
3

Ada cara lain untuk melakukannya. Suka:

echo ${opt:1:-1}
DevilTour
sumber
2

Versi saya

strip_quotes() {
    while [[ $# -gt 0 ]]; do
        local value=${!1}
        local len=${#value}
        [[ ${value:0:1} == \" && ${value:$len-1:1} == \" ]] && declare -g $1="${value:1:$len-2}"
        shift
    done
}

Fungsi menerima nama variabel dan tanda kutip di tempat. Itu hanya menghapus sepasang kutipan terkemuka dan tertinggal. Itu tidak memeriksa apakah kutipan tambahan lolos (didahului oleh\ mana itu sendiri tidak lolos).

Dalam pengalaman saya, fungsi utilitas string untuk keperluan umum seperti ini (saya punya perpustakaannya) paling efisien ketika memanipulasi string secara langsung, tidak menggunakan pencocokan pola apa pun dan terutama tidak membuat sub-shell, atau memanggil alat eksternal seperti sed, awkatau grep.

var1="\"test \\ \" end \""
var2=test
var3=\"test
var4=test\"
echo before:
for i in var{1,2,3,4}; do
    echo $i="${!i}"
done
strip_quotes var{1,2,3,4}
echo
echo after:
for i in var{1,2,3,4}; do
    echo $i="${!i}"
done
Gene Pavlovsky
sumber
0

Saya tahu ini adalah pertanyaan yang sangat lama, tetapi di sini ada variasi sed yang lain, yang mungkin berguna bagi seseorang. Tidak seperti beberapa yang lain, itu hanya menggantikan tanda kutip ganda pada awal atau akhir ...

echo "$opt" | sed -r 's/^"|"$//g'
pengguna1751825
sumber