web-dev-qa-db-ja.com

変数内の文字を置き換える最短の方法

変数の文字を置き換える方法はたくさんあります。

私が見つけた最短の方法はこれまでのところtrです:

OUTPUT=a\'b\"c\`d_123and_a_lot_more
OUTPUT=$(echo "$OUTPUT"|tr -d "'\`\"")
echo $OUTPUT

より速い方法はありますか?そして、これは'"や `自体のような引用に対して安全ですか?

19
rubo77

どれどれ。私が思いつくことができる最短のものは、あなたの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

違いはわずかなので、上記のテストを2つそれぞれについて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を使用しますが、変数に再割り当てする場合は、シェルの文字列操作機能を使用すると、別のサブシェルを実行するオーバーヘッドを回避できるため、より高速になります。

22
terdon

変数置換 を使用できます:

$ 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
15
chaos

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
12
gena2x