Gnu sedは値を追加するbash関数を実行できます。

Gnu sedは値を追加するbash関数を実行できます。

gnu sedはどのようにbash関数を実行してカウンタ値を増やすのですか?

$ k(){ ((i++)); echo $i ;} ;export -f k
$ i=; echo -e 'oAo\nooAo\nAo' | sed -E '/A/e k'
1
oAo
1
ooAo
1
Ao

カウンタを正しく実行する代わりに失敗します。

答え1

プロセスは親プロセスの環境に影響を与えることはできません。 sedのコマンドを使用すると、新しい eシェルをフォークしてコマンドを実行し(エクスポートされたk関数を継承します)、そのシェル変数に対するすべての変更はi終了時に失われます(つまり、k関数はhourを終了します)。

変数を増やすには、環境外のどこかに変数を保存する必要があります。たとえば、ファイルから。ファイルを使用したくない場合は、SQLデータベースなどを使用できない理由はmemcachedありませんredis

例えば:

k() {
  local counterfile i
  counterfile='/tmp/counter.i'
  [ -e "$counterfile" ] && i=$(cat "$counterfile")
  ((i++))
  echo "$i" | tee "$counterfile"
}
export -f k

今実行するとカウンタが増えます。

$ rm /tmp/counter.i
$ printf 'oAo\nooAo\nAo' | sed -E '/A/e k'
1
oAo
2
ooAo
3
Ao
$ echo 100 > /tmp/counter.i
$ printf 'oAo\nooAo\nAo' | sed -E '/A/e k'
101
oAo
102
ooAo
103
Ao

ところで、sedのeコマンドは役に立ちますが、私の考えにはPerlがあなたがしている作業にもっと良い言語だと思います。例えば

$ printf 'oAo\nooAo\nAo' |
    perl -lpe 'BEGIN { $i=shift || 0 };
               if (/A/) {print ++$i}' 10
11
oAo
12
ooAo
13
Ao

引数を指定しない場合、$iデフォルトは0です。

スクリプトが「sed」のように見えるようにするには、埋め込み行$iにカウンタ変数をインクリメントして印刷する方法がありますA。ここに別のものがあります:

/A/ && print ++$i

1行に複数の一致がある可能性があり、各一致に対してカウンタを増やして印刷する必要がある場合は、一致を繰り返す必要があります。例えば

$ printf 'oAo\noAoAoAo\nAo' |
    perl -lpe 'BEGIN { $i=shift || 0 };
               for (/oA/g) {print ++$i}'
1
oAo
2
3
4
oAoAoAo
Ao

または累積合計は必要ありませんが、各行の一致数を数える場合:

$ printf 'oAo\noAoAoAo\nAo' |
    perl -lne '$c = () = $_ =~ /oA/g;
               printf "%02i:%s\n", $c, $_'
01:oAo
03:oAoAoAo
00:Ao

この最後の項目には説明が必要な場合があります。読む戻る、この$c = () = $_ =~ /oA/gステートメントは最初に正規表現一致を実行し/oA/g、リストコンテキストの結果を空のリストとして返し、変数に()割り当てます$c。配列/リストではなくスカラー変数であるため、スカラー$cコンテキストで評価されるため、そのリストの要素数を返します。これは、一致の数を計算するために使用される非常に一般的なPerl慣用語です。


注:Perlには、-psedと非常によく似た方法で実行するオプションがあります(つまり、入力を繰り返して文が印刷を妨げない限り、処理後に各行を印刷します)。 Perlには-n次のように動作させるオプションがありますsed -n(入力を繰り返して明示的に印刷するように指示するだけ)。

最後に、このバージョンのsedおよびbash関数は、一致する各入力行に対して、およびを分岐することbashcat注目する価値があります。 Perlバージョンは何もフォークせず、入力だけを繰り返します。 bashで実行するために外部プログラムをフォークする必要がある多くの作業は、独自の組み込み構文(または数千のライブラリモジュールのいずれか)を使用してPerlを介して内部的に実行できることにも注目に値します。tee/A/

答え2

GNU sedを使用すると、目的の結果を得るためにユーザー定義関数に頼る必要はありません。ここでは、増分数を格納するためにストレージスペースを使用します。

echo -e 'oAo\nooAoAoA\no' | 
sed -En "/A/!d
  p;:a
  H;g
  s/^(\n*).*/expr '\1' : '.*'/ep
  g;s//\1/;x;s/^\n*//;s/A//;//ba
"

出力:

oAo
1
ooAoAoA
2
3
4

関連情報