sed
3桁より長い数字を16進数に変換するコマンドを作成しようとしています。つまり、このような文字列は現在私が持っている124 3275 7535
もの124 0xccb 0x1d6f
です。
sed 's@\([0-9]\{4,\}\)@sh -c "printf 0x%x \1"@ge'
ただし、文字列が一致しない場合は、変更されていない文字列を外部コマンドとして実行しようとするため、上記の文字列例では次のような結果が得られます。
sh: 1:124: 見つかりません
私がしたいことをどのように達成できますか? (まだsed
?
答え1
質問のタイトルによると、「with sed」ではありませんが、sedからPerlに切り替えると、次の同等の表現を使用できます。
perl -p -e 's/\b\d{4,}\b/sprintf "%#x", $&/ge'
これにより、チェーンの他の式をある程度保存できます。
答え2
コマンドフラグのGNU実装はe
評価です。s
sed
パターン空間の内容置換を(成功的に)適用し、評価の代わりにパターン空間を出力に置き換えた後置換。
ここでは、次の入力について:
foo 1234 123
以下を含むパターン空間を作成するには、置換が必要です。
printf %s 'foo '
printf 0x%x 1234
printf %s ' 123'
シェルコマンドでe
これをフラグに変換します。foo 0x3d2 123
不可能ではありません。たとえば、次のようになります。
LC_ALL=C sed -E "
/[0-9]{4}/!b # optimisation
s/'/&\\\\&/g
s/[0-9]{4,}/'\nprintf 0x%x &\nprintf %s '/g
s/.*/printf %s '&'/e"
しかし、これはやや厄介で、一致する各入力行に対してシェルを実行することを意味します。 GNUismを使用せずに次のことができます。
LC_ALL=C sed "
s/'/&\\\\&/g
s/[0-9]\{4,\}/'\\
printf 0x%x &\\
printf %s '/g
s/.*/printf %s '&\\
'/" | sh
どちらが実行されるのか一つ sh
。
また、このようにランダムなデータをシェルコードで評価することは私を緊張させる傾向があります。たとえば、上記のLC_ALL = Cがないと、ランダムなコマンド実行の脆弱性が発生します。たとえば、次のような出力を試してみてください。
printf '0000\200; echo GOTCHA>&2\n'
UTF-8ロケール。
ここでは、次のようなものを使用することをお勧めしますperl
。
perl -pe 's/\d{4,}/sprintf "0x%x", $&/ge'
perl
ロゴはe
あなたの期待にもっと合います。代替エントリをコードで評価します(そして、perl
GNUのように毎回新しいPerlインタプリタを起動しません)。sed
e
答え3
awk
それ正確にこのタイプの広範なテキスト操作です。補助ツールにパイプを接続する必要はありません。
awk '{ for( fn=1;fn<=NF;fn++ ){
fmat=(length($fn)>3)?"0x%x":"%s"
dlim=(fn==NF?"\n":" ")
printf( fmat dlim, $fn )}}' <<<'124 3275 7535'
あなたの例に基づいて出力:
124 0xccb 0x1d6f
答え4
私はPeter.Oがコメントで言ったことに同意します。これは1つの方法です(各数字の末尾にある必要がbash
あります)。
echo '124 3275 7535 ' | while read -d ' ' x; do [ ${#x} -ge 4 ] && printf "0x%x " $x || printf "%d " $x; done
入力ストリームの行の末尾(例では)がない場合に
sed
便利です。
echo '124 3275 7535' | sed 's/$/ /' | while read -d ' ' x; do [ ${#x} -ge 4 ] && printf "0x%x " $x || printf "%d " $x; done