sedを使用して長い数字を16進数に変換する

sedを使用して長い数字を16進数に変換する

sed3桁より長い数字を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評価です。ssedパターン空間の内容置換を(成功的に)適用し、評価の代わりにパターン空間を出力に置き換えた後置換

ここでは、次の入力について:

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あなたの期待にもっと合います。代替エントリをコードで評価します(そして、perlGNUのように毎回新しいPerlインタプリタを起動しません)。sede

答え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

関連情報