シェルスクリプト-変数から最初と最後の引用符( ")を削除します


225

以下は、より大きなスクリプトからのシェルスクリプトのスニペットです。変数によって保持されている文字列から引用符を削除します。私はsedを使用してそれをやっていますが、それは効率的ですか?そうでない場合、効率的な方法は何ですか?

#!/bin/sh

opt="\"html\\test\\\""
temp=`echo $opt | sed 's/.\(.*\)/\1/' | sed 's/\(.*\)./\1/'`
echo $temp

を使用することをお勧めしsed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt"ます。この構文は、一致するペアがある場合にのみqoutesを削除します。
ジョンスミス

@JohnSmithまた、シェルスクリプトで引用符を自動的にエスケープする必要がありますが、引用符が一致するかどうかにかかわらずエスケープする必要があるため、投稿した式はおそらく使用しません。
Pysis 2017年

すべての引用を削除したいだけのときにこの質問を見つけた場合は、この回答を参照してください:askubuntu.com/a/979964/103498
ゴードンビーン

回答:


268

ネイティブシェルのプレフィックス/サフィックスの削除機能を使用して、より簡単で効率的な方法があります。

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

${opt%\"}サフィックスを削除します"(シェルの解釈を防ぐためにバックスラッシュでエスケープされます)。

${temp#\"}プレフィックスを削除します"(シェルの解釈を防ぐためにバックスラッシュでエスケープされます)。

別の利点は、周囲の引用符がある場合にのみ、周囲の引用符が削除されることです。

ところで、ソリューションでは常に最初と最後の文字が削除されます(もちろん、私はあなたがデータを知っていると確信していますが、何を削除するかを確認することは常に優れています)。

sedの使用:

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

(jfgagneで示されているように、エコーを取り除く改良版)

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

ですから、先頭"を何も入れず、末尾"を何も入れ替えません。同じ呼び出しで(別のsedをパイプして開始する必要はありません。使用-eすると、複数のテキスト処理を行うことができます)。


14
でsedソリューションのパイプを取り除くことができますsed -e 's/^"//' -e 's/"$//' <<< $opt
jfg956

1
これは、文字列に先頭と末尾の両方の引用文字がないと誤動作する可能性があります。それを優雅に処理するための提案はありますか?
jsears

一致する外側の引用のみを処理するには、@ Joachim Pileborgによる回答を参照してください
jsears

1
@jsearsハァッ?具体的には、1つある場合は最初から1つ、1つある場合は最後から1つトリミングします。両方が存在しない限り、削除したくない場合。はい、単一のsed正規表現を使用するか、変数置換を何かの行にラップすることができますcase $opt in '"'*'"') ... do it ... ;; esac
tripleee

2
次を使用することにより、複数の式を回避できますsed 's/^"\|"$//g'
tzrlk

287

trを使用して削除し"ます。

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

:これにより、先頭と末尾だけでなく、すべての二重引用符が削除されます。


16
これはOPが要求したものではありません。先頭と末尾の引用だけでなく、すべての引用も削除されるからです。
Lenar Hoyt

19
「/ path / file-name」の最初と最後に二重引用符しかないため、OPに明示的に応答しなくても、これで解決します。埋め込まれた二重引用符はありません。+1
WinEunuuchs2Unix 2017

6
このソリューションは、多くの人が求めるものです。多くの場合、スクリプトは、実行可能なデータを引用符で囲まれた文字列に簡単に変換できます。
Shadoninja

2
エレガントで、より多くの試行錯誤のデバッグ時間から私を救いました。どうも。
スコットウェイド

これが理想的なものであり、それが認められた回答よりも多くの票を持つ理由です。
apurvc '13 / 11/19

38

これにより、すべての二重引用符が削除されます。

echo "${opt//\"}"

1
ただし、エスケープされた引用符で壊れDon't remove this \" quoteます。:-(
gniourf_gniourf 2012

これはBashの拡張機能であるため、一般的なシェルスクリプトには適用されません。(これが重要かどうかについての質問は曖昧です。Googleでこれを見つけた訪問者はPOSIXソリューションを探しているかもしれません。)
tripleee

完璧!まさに私が必要としたもの。OPが要求したものだけでなく、多くの答えを与えるこのような質問が大好きです。宝石は受け入れられない答えにあります!
dlite922

OPが先頭/末尾の引用符のみを削除し、エスケープされた引用符を保持するものを望んでいると思います。
Fernando Paz

36

xargsを使用する簡単な方法があります:

> echo '"quoted"' | xargs
quoted

xargsは、コマンドが提供されていない場合、デフォルトのコマンドとしてechoを使用し、入力から引用符を取り除きます。例えばここを参照してください。


echo '"quoted"' | xargs -> quoted
kyb 2018

1
これは機能しますが、文字列内の偶数の引用符に対してのみです。奇数の場合はエラーになります。
ジェームズShewey


19

最短の方法 -試してみてください:

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

それは実際にすべて"のs(二重引用符)を削除します(optただし、最初と最後以外に二重引用符が本当にあるのでしょうか?それで実際には同じことであり、はるかに簡単です;-))


4
すべての二重引用符を削除する場合は、「$ {opt // \ "/}」を使用することをお勧めします。パイプなし、サブシェルなし...そして、optにスペースがある場合、失う可能性があることに注意してください常に次のような変数を引用します:echo "$ opt"
huelbois

まあ、変数は基本的にhttpdの構成ファイルからDocumentRootのパスを読み取るため、文字列内に引用符文字が含まれている可能性があるとは思えません。そして、このsedはよりすっきりとして効率的です。
user1263746 2012年

16

jqを使用していて、結果から引用符を削除しようとしている場合、他の答えは機能しますが、より良い方法があります。この-rオプションを使用すると、引用符なしで結果を出力できます。

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

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

私は使用してjqいますが、jqがASCII出力を出力している場合は機能しません-a(jq側のバグです)
CanPoyrazoğluApr

yqまた、持っている-rオプション:yq -r '.foo' file.yml
Hlib Babii

12

更新

bash /標準のLinuxコマンドのみを使用して文字列内の単一引用符と二重引用符を取り除くことによるシンプルでエレガントな答え:

BAR=$(eval echo $BAR) 引用符を取り除きます BAR

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

hueyboisの答えに基づいて、私は多くの試行錯誤の後でこの関数を思いつきました:

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

何も印刷したくない場合は、evalをパイプして /dev/null 2>&1

使用法:

$ BAR="FOO BAR"
$ echo BAR
"FOO BAR"
$ stripStartAndEndQuotes "BAR"
$ echo BAR
FOO BAR

1
私は本当にシンプルでエレガントなのが好きですが、evalは単に二重引用符のトリミングを行うのではなく、実際にはコード行として評価されることに注意する価値があります。したがって、BARがシェルによって置換される可能性のある他のシーケンス(たとえば、BAR = \ 'abc \'またはBAR = ab \ 'cまたはBAR = a \ $ b、またはBAR = a \ $(ls *))
MaxP 2017年

11

Bashの最も簡単なソリューション:

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

これは部分文字列展開と呼ばれます(Gnu Bashマニュアルを参照してを検索してください${parameter:offset:length})。この例では、部分文字列sを位置1 から開始し、最後から2番目の位置で終了します。これはlength、が負の値の場合、の末尾から逆方向に実行されるオフセットとして解釈されるためですparameter


bash v4.2からサポートされる負の長さ
mr.spuratic

8

これは、sedを使用しない最も離散的な方法です。

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

または

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

出力:

   quotes: "fish"
no quotes:  fish

これはソースから入手しまし


これにより、文字列内およびその周囲の引用符が削除されます。
jsears

解説を除いて、これは2012年の@StevenPennyの回答と同じです。
tripleee 2016年

3

それを行う別の方法があります。お気に入り:

echo ${opt:1:-1}

2

私のバージョン

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
}

関数は変数名を受け入れ、引用符を削除します。一致する先行引用符と後続引用符のペアのみが削除されます。末尾の引用がエスケープされているかどうかはチェックされません(前に\ている自体がエスケープていない)。

私の経験では、このような汎用の文字列ユーティリティ関数(それらのライブラリがあります)は、文字列を直接操作する場合、パターンマッチングを使用しない場合、特にサブシェルを作成しない場合、または次のような外部ツールを呼び出す場合に最も効率的ですsedawkまたは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

0

私はこれが非常に古い質問であることを知っていますが、これは誰かに役立つかもしれない別のsedバリエーションです。他のいくつかとは異なり、それは最初または最後の二重引用符を置き換えるだけです...

echo "$opt" | sed -r 's/^"|"$//g'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.