二重引用符内で二重引用符をエスケープするにはどうすればよいですか?


286

Bashで二重文字列内の二重引用符をエスケープするにはどうすればよいですか?

たとえば、私のシェルスクリプトで

#!/bin/bash

dbload="load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"

ENCLOSED BY '\"'二重引用符で正しくエスケープすることができません。variableを使用したいので、変数に単一引用符を使用できません$dbtable




2
@kenorbその質問の複製のように見えません...
マーク


@Daenythこれは、エンドユーザーがアクセスすることを期待するコマンドのタイプではありません。一括読み込みスクリプトは通常、信頼できるユーザー(システム管理者や開発者など)によってサーバーで実行されます。はい、エンドユーザーがの値を制御している場合$dbtable、リスクがあります。ただし、エンドユーザーは通常、マシンにSSHで接続してデータをロードしないため、これは非常にまれです。
jpmc26 2017

回答:


285

バックスラッシュを使用します。

echo "\""     # Prints one " character.

9
機能していません。x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi;壊れているの... [ -f "$(which $x)" ]; ...か、... [ -f $(which "$x") ]; ...うまくいくか 問題が発生するのは、スペースの$x結果$(which "$x")やその他の特殊文字が含まれている場合、またはその結果が何かである場合です。回避策はの結果を保持するために変数を使用することですがwhich、bashは引用符をエスケープすることが本当にできないのですか、それとも私は何か間違っているのですか?
Luc、

grep -oh "\"\""$counter"\""\w*" in $counterが変数であるbash構文の一部として次を使用しようとしています。それはそれを好きではありません
ジェイD

82

シェルで引用符をエスケープする簡単な例:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

これは、既に開いているもの(')を終了し、エスケープされたもの(\')を配置してから、別のもの(')を開くことによって行われます。

または:

$ echo 'abc'"'"'abc'
abc'abc
$ echo "abc"'"'"abc"
abc"abc

それは、すでに開いているものを終了し(')、別の引用符に引用符を配置し("'")、次に別の引用符を開く()ことによって行われ'ます。

その他の例:単一引用符で囲まれた文字列内の単一引用符のエスケープ


1
私はsh -c "echo '{" key ":" value "}'"を試し、sh -c "echo '{' '"' 'key' '"' ':' '"' 'value' '"'も試しました'}' "は、keyとvalueという単語を二重引用符で囲むように努力しましたが、どちらの場合も{key:value}を取得しました
Igor Yagolnitser

1
これは二重引用符では不必要に複雑に見えます。ピーターの回答のecho "abc\"abc"ように生成するには十分abc"abcです。
divenex '19年

2
確かにこの単純な例では、ネストされた引用の複雑なケースでは、これを行う必要がある場合があり、@ kenorbの例は、これらのケースを処理する方法を理解するのに役立ちました。
prosoitos

63

この古い問題がなぜBashタグ付きリストに今日現れたのかはわかりませんが、将来の研究者のために、エコーする必要のある文字のASCIIコードを使用することでエスケープを回避できることに注意してください。

例:

 echo -e "This is \x22\x27\x22\x27\x22text\x22\x27\x22\x27\x22"
 This is "'"'"text"'"'"

\x22二重引用符と\x27単一引用符のASCIIコード(16進数)です。同様に、任意の文字をエコーできます。

上記の文字列をバックスラッシュでエコーしようとすると、バックスラッシュされた厄介な2行のエコーが必要になります... :)

変数割り当ての場合、これは同等です。

 $ a=$'This is \x22text\x22'
 $ echo "$a"
 This is "text"

変数がすでに別のプログラムによって設定されている場合でも、sedまたは同様のツールを使用して二重/単一引用符を適用できます。

例:

 $ b="Just another text here"
 $ echo "$b"
 Just another text here
 $ sed 's/text/"'\0'"/' <<<"$b" #\0 is a special sed operator
 Just another "0" here #this is not what i wanted to be
 $ sed 's/text/\x22\x27\0\x27\x22/' <<<"$b"
 Just another "'text'" here #now we are talking. You would normally need a dozen of backslashes to achieve the same result in the normal way.

1
+1は、PS1変数を〜/ .profileに追加する問題を解決したため echo 'export PS1='\[\033[00;31m\]${?##0}$([ $? -ne 0 ] && echo \x22 \x22)\[\033[00;32m\]\u\[\033[00m\]@\[\033[00;36m\]\h\[\033[00m\][\[\033[01;33m\]\d \t\[\033[00m\]] \[\033[01;34m\]\w\n\[\033[00m\]$( [ ${EUID} -ne 0 ] && echo \x22$\x22 || echo \x22#\x22 ) '' >> ~/.profile
Yassine ElBadaoui

1
これが答えです!私はあなたを愛しています。
ミゲルロハスコルテス

28

Bashを使用すると、ストリングを隣接して配置することができ、ストリングが接着されてしまいます。

したがって、この:

$ echo "Hello"', world!'

作り出す

Hello, world!

トリックは、必要に応じて単一引用符と二重引用符で囲まれた文字列を交互に使用することです。残念ながら、それはすぐに非常に複雑になります。例えば:

$ echo "I like to use" '"double quotes"' "sometimes"

作り出す

I like to use "double quotes" sometimes

あなたの例では、私は次のようにします:

$ dbtable=example
$ dbload='load data local infile "'"'gfpoint.csv'"'" into '"table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"'"'"' LINES "'TERMINATED BY "'"'\n'"'" IGNORE 1 LINES'
$ echo $dbload

次の出力が生成されます。

load data local infile "'gfpoint.csv'" into table example FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "'\n'" IGNORE 1 LINES

ここで何が起こっているのかを理解することは困難ですが、Unicodeの引用符を使用して注釈を付けることができます。以下はbashでは機能しません–説明のためだけです:

dbload=' load data local infile "'“ 'gfpoint.csv'” ' " into'“ table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '” ' "'“ ' LINES” ' TERMINATED BY "'“ '\n'” ' " IGNORE 1 LINES'

上記の「 ''」のような引用符はbashによって解釈されます。のような引用符" 'は、結果として得られる変数で終わります。

前の例と同じ扱いをすると、次のようになります。

$ echoI like to use"double quotes"sometimes


4
うーん...それはいくつかの醜いものです。
魔法のタコの壺

17

printfを確認してください...

#!/bin/bash
mystr="say \"hi\""

printfを使用しない場合

echo -e $mystr

出力:「こんにちは」と言う

使用する printfの

echo -e $(printf '%q' $mystr)

出力:「hi」と言います


2
printfにも多くの文字をエスケープする、など'(及び)
デヴィッドPärsson

printf %qevalにフォーマットされていない、の準備が整ったストリングを生成しますecho -e
Charles Duffy

2
printfをの無駄な使用でechoラップする理由はありません。どちらの例も引用が壊れています。適切な修正は、変数を二重引用符で囲むことです。
tripleee 2017年

15

二重引用符を変数として保存します。

dqt = '"'
echo "二重引用符で囲まれた文字列内の$ {dqt} X $ {dqt}を二重引用符で囲みます"

出力:

二重引用符で囲まれた文字列内の「X」を二重引用符で囲みます

39
Bashは本当に最悪の言語です
Andy Ray

@ 12oclocker、あなたの答えは絶対確実です:D!特に「sed」コマンドで使用すると、1日が節約できました。
Artanis Zeratul

11

$ "string"を利用してください。

この例では、

dbload = $ "load data local infile \" 'gfpoint.csv' \ "into table $ dbtable FIELDS TERMINATED BY '、' ENCLOSED BY '\"' LINES TERMINATED BY \ "'\ n' \" IGNORE 1 LINES "

注(manページから):

ドル記号が前に付いた二重引用符で囲まれた文字列($ "string")は、現在のロケールに従って文字列を翻訳します。現在のロケールがCまたはPOSIXの場合、ドル記号は無視されます。文字列が翻訳および置換される場合、置換は二重引用符で囲まれます。


3
いいですね、それは知りませんでした。
David Kierans

-5

"\"二重引用符の前に追加してエスケープする代わりに\

#! /bin/csh -f

set dbtable = balabala

set dbload = "load data local infile "\""'gfpoint.csv'"\"" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"\""' LINES TERMINATED BY "\""'\n'"\"" IGNORE 1 LINES"

echo $dbload
# load data local infile "'gfpoint.csv'" into table balabala FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "''" IGNORE 1 LINES

6
反対票:なぜ質問へのcsh回答を投稿するのbashですか?2つは完全に異なり、互換性がありません。
tripleee 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.