変数から文字を削除する方法はいくつかあります。
これまで私が見つけた最も短い方法は次のとおりです。tr
:
OUTPUT=a\'b\"c\`d_123and_a_lot_more
OUTPUT=$(echo "$OUTPUT"|tr -d "'\`\"")
echo $OUTPUT
より速い方法がありますか?
'
この引用は、およびそれ自体の"
ような引用に安全ですか`
?
答え1
みましょう。私が考えることができる最も短いのは、ソリューションを適用したことですtr
。
OUTPUT="$(tr -d "\"\`'" <<<$OUTPUT)"
他の選択肢には、すでに述べた変数置換が含まれています。
OUTPUT="${OUTPUT//[\'\"\`]}"
もちろん、sed
これは文字の面でより長いです。
OUTPUT="$(sed s/[\'\"\`]//g <<<$OUTPUT)"
最小長さを意味するのか、最小時間を意味するのか分かりません。長さの観点からこれらの特定の文字を削除すると、これらの2つの文字は可能な限り短くなります(または私が得ることができるすべて)。それでは、どちらが最速ですか?変数を例の変数に設定してOUTPUT
テストしましたが、何十回も繰り返しました。
$ echo ${#OUTPUT}
4900
$ time tr -d "\"\`'" <<<$OUTPUT
real 0m0.002s
user 0m0.004s
sys 0m0.000s
$ time sed s/[\'\"\`]//g <<<$OUTPUT
real 0m0.005s
user 0m0.000s
sys 0m0.000s
$ time echo ${OUTPUT//[\'\"\`]}
real 0m0.027s
user 0m0.028s
sys 0m0.000s
お分かりのように、tr
明らかに最も速く、次のものですsed
。またecho
、実際には以下を使用するよりも少し速いようです<<<
。
$ for i in {1..10}; do
( time echo $OUTPUT | tr -d "\"\`'" > /dev/null ) 2>&1
done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}';
0.0025
$ for i in {1..10}; do
( time tr -d "\"\`'" <<<$OUTPUT > /dev/null ) 2>&1
done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}';
0.0029
違いが小さいため、両方のテストに対して上記のテストを10回実行した結果、最速のテストは実際に開始する必要があるテストであることがわかりました。
echo $OUTPUT | tr -d "\"\`'"
ただし、変数に割り当てるオーバーヘッドを考慮すると、状況が異なります。ここでの使用はtr
単純な交換よりも少し遅いです。
$ for i in {1..10}; do
( time OUTPUT=${OUTPUT//[\'\"\`]} ) 2>&1
done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}';
0.0032
$ for i in {1..10}; do
( time OUTPUT=$(echo $OUTPUT | tr -d "\"\`'")) 2>&1
done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}';
0.0044
したがって、要約すると、結果だけを見たいときに使用し、tr
変数に再割り当てしたいときは別のサブシェルを実行するオーバーヘッドを避けるため、シェルの文字列操作機能を使用する方が高速です。
答え2
使用できる変数の置換:
$ OUTPUT=a\'b\"c\`d
$ echo "$OUTPUT"
a'b"c`d
次の構文を使用します。${parameter//pattern/string}
パターン内のすべての項目を文字列に置き換えます。
$ echo "${OUTPUT//\'/x}"
axb"c`d
$ echo "${OUTPUT//\"/x}"
a'bxc`d
$ echo "${OUTPUT//\`/x}"
a'b"cxd
$ echo "${OUTPUT//[\'\"\`]/x}"
axbxcxd
答え3
Bashまたはzshでは、次のようになります。
OUTPUT="${OUTPUT//[\`\"\']/}"
このパターンのすべてのインスタンスが${VAR//PATTERN/}
削除されます。より多くの情報を知りたい場合Bash パラメータ拡張
このソリューションには外部プログラムの実行が含まれていないため、短い文字列の場合は最も高速です。しかし、非常に長い文字列の場合はその逆になります。テキスト操作用の専用ツールを使用する方が良いです。たとえば、次のようになります。
$ OUTPUT="$(cat /usr/src/linux/.config)"
$ time (echo $OUTPUT | OUTPUT="${OUTPUT//set/abc}")
real 0m1.766s
user 0m1.681s
sys 0m0.002s
$ time (echo $OUTPUT | sed s/set/abc/g >/dev/null)
real 0m0.094s
user 0m0.078s
sys 0m0.006s
答え4
場合によっては、シェルで引用符を再利用する問題を処理したい場合は、次のようにします。いいえ削除するのも非常に簡単です。
aq() { sh -c 'for a do
alias "$((i=$i+1))=$a"
done; alias' -- "$@"
}
関数シェルは、渡されたすべての引数の配列を参照し、反復可能な各引数の出力を増やします。
以下はいくつかのパラメータです。
aq \
"here's an
ugly one" \
"this one is \$PATHpretty bad, too" \
'this one```****```; totally sucks'
出力
1='here'"'"'s an
ugly one'
2='this one is $PATHpretty bad, too'
3='this one```****```; totally sucks'
この出力は通常、dash
安全引用符で囲まれた単一引用符出力から来ます'"'"'
。bash
'\''
$IFS
とを使用するすべてのPOSIXシェルでは、空白ではなくnull以外の選択された単一バイトを別の単一バイトに置き換えることがおそらく最速です$*
。
set -f; IFS=\"\'\`; set -- $var; printf %s "$*"
出力
"some ""crazy """"""""string ""here
私はただprintf
あなたが見ることができるようにそこに置くだけですが、もちろんこうすれば次のようになります。
var="$*"
printf
...コマンドの代わりに、$var
値は出力に表示される値になります。
私がset -f
シェルに指示したときいいえto glob - 文字列にglobパターンとして解釈できる文字が含まれている場合。シェルパーサーがglobパターンを拡張するので、これを行います。後ろに変数に対してフィールド分割を実行します。ワイルドカードは次のように再度有効にできますset +f
。通常、スクリプトで前髪を次のように設定すると便利です。
#!/usr/bin/sh -f
だから明示的にワイルドカードを有効にするset +f
私が望むすべての行に関連しています。
フィールド分割はの文字に基づいています$IFS
。
スペースとスペース以外の2つの$IFS
値があります。スペース$IFS
$IFS
$IFS
(スペース、タブ、改行)省略されたと指定されたフィールド区切り注文する単一フィールドとして(または他のものより前にない場合はまったくありません)- だから...
IFS=\ ; var=' '; printf '<%s>' $var
<>
ただし、他のすべての項目は単一のフィールドを評価するように指定されています。毎回- 切れません。
IFS=/; var='/////'; printf '<%s>' $var
<><><><><>
みんなデフォルトでは、変数拡張は$IFS
区切りデータ配列です$IFS
。 -quote で引用すると、配列"
属性をオーバーライドして単一の文字列として評価します。
だから私がこれをするとき...
IFS=\"\'\`; set -- $var
シェルの引数配列を$IFS
拡張で生成された区切りフィールドの数に設定しました。$var
拡張すると、埋め込み文字の構成$IFS
値は次のようになります。失われた- 今は単なるフィールド区切り記号です。です\0NUL
。
"$*"
- 他の二重引用符変数の拡張と同様に - もオーバーライドされます$IFS
。また、最初のバイトを置き換えます。$IFS
区切られた各フィールドについて存在する"$@"
。"
だからこそ最初値は$IFS
以降のすべての区切り記号"
は"$*"
。分割時に"
その中に含める必要もありません。$IFS
あなたは変更することができます$IFS
後ろに set -- $args
全く異なる値で新しいこれにより、最初のバイトがフィールド区切り記号として表示されます"$*"
。さらに、次のようにすべてのトレースを完全に削除できます。
set -- $var; IFS=; printf %s "$*"
出力
some crazy string here