web-dev-qa-db-ja.com

パイプの出力から部分文字列をエコーする方法は?

私は here bashで部分文字列を抽出する方法を見つけましたが、これをパイプの後に適用する方法について迷っています。例えば:

some func | echo ${string:12:5}

some funcの出力を変数stringに割り当てるにはどうすればよいですか?

2
Michael Hays

_${string:offset:length}_は、_$string_変数の文字の範囲に展開されるパラメーター展開演算子です。

入力からbytesの範囲を取得するには(シングルバイト文字にも適用されます)、以下を使用できます。

_func | tail -c +12 | head -c 5
_

12バイト目から始まる5バイトを取得します(1ベースのオフセット)。 headの_-c_オプションは標準ではありませんが、かなり一般的です。

funcは、16バイト目を出力した後、いつか強制終了される可能性があることに注意してください。これらの5バイトを出力した後、headが終了し、その後、さらにデータを書き込もうとすると、tailが強制終了され、funcに波及します。

次のこともできます:

_func | dd bs=1 skip=11 count=5 2> /dev/null
_

_2> /dev/null_は、最後のステータスメッセージを回避するためのものです。ただし、すべてのエラーが抑制されます。 GNU ddを使用すると、これを_status=none_に置き換えることで、ステータスのみを抑制できます。

lengthの値が大きい場合、一度に1バイトを読み取るため、効率が低下します。 GNU ddを使用すると、次のようにして回避できます。

_func | dd iflag=count_bytes,skip_bytes,fullblock skip=11 bs=64k count=5M status=none
_

これは、最大64KiBの読み取りを行い、5MiBバイトのデータを取得します。

これらのオフセットと長さをバイトではなく文字(シングルバイトまたはマルチバイト)で表現する場合、これはさらに複雑になります。

オプションは、出力全体を変数に格納し、_${var:offset:length}_演算子を使用することです 他の人が示したように 。ただし、これは出力全体をメモリに格納することを意味します。 var=$(func)を使用すると、末尾の改行文字が破棄されます。

別のオプションは、指定された数の文字を読み取るbashの_read -N_を使用することです

_func | {
  IFS= read -rN 11 discarded
  IFS= read -rN 5 data
  printf '%s\n' "$data"
}
_

またはPerlを使用します(大きなデータの場合は少し効率的です):

_func | Perl -Mopen=locale -sne '
  BEGIN{$total = $o + $n; $/ = \$total}
  print substr($_, $o); exit' -- -o=10000 -n=5000000
_
4

回答

some_funcからの出力のみを抽出する場合は、変数に保存する必要はありません。出力をcutに送信するだけで、要求された文字を抽出できます。

some_func | cut -c 12-16  

説明

cutstdinを受け取り、指定されたオプションに基づいて要求された範囲を抽出します。

-c範囲が文字で指定されていることを意味します。

12-16文字が1ではなく、インデックス0で始まる範囲。
したがって、これは12131415および16の位置にある文字を受け取ります。

StéphaneChazelas が私に残ったので、これは最初の行だけでなく、入力の各行でも機能することに注意してください。

3
Iskustvo
string="$(func)"
echo "${string:12:5}"
2
DopeGhoti