各行に文字列を追加するコマンド?


36

このようなものをお探しですか?何か案は?

cmd | prepend "[ERRORS] "

[ERROR] line1 text
[ERROR] line2 text
[ERROR] line3 text
... etc

bash関数/スクリプトのすべてのコマンドにこれを設定する方法はありますか?
アレクサンダーミルズ

回答:


39
cmd | while read line; do echo "[ERROR] $line"; done

bashビルトインのみを使用する利点があるため、作成/破棄されるプロセスが少なくなるため、awkやsedよりも速くタッチする必要があります。

@tzrikは、それが素敵なbash関数を作成することもあると指摘しています。次のように定義します:

function prepend() { while read line; do echo "${1}${line}"; done; }

次のように使用できるようになります。

cmd | prepend "[ERROR] "

4
これは実際にはプロセス数を1つだけ減らします。(ただし、正規表現(sed)または文字列分割(awk)も使用されていないため、高速になる可能性があります。)
grawity

ところで、パフォーマンスに興味があり、bash、sed、awkを使用した簡単なベンチマークの結果を次に示します。約1000行のテキスト(dmesg出力)をFIFOファイルにプッシュし、次のように読み取ります:pastebin.ca/1606844 awkが勝者のようです。なぜアイデアがありますか?
イリヤザクレウスキ2009年

1
そのようなタイミングテストを慎重に実行してください-6つすべての異なる順序で実行し、結果を平均してみてください。ブロックキャッシュの影響を緩和し、バックグラウンドの中断/スケジューリングの影響を緩和するために平均するためのさまざまな順序。
pjz

この質問には「bash」ではなく「shell」というタグが付けられています。
フィアットヤフ

1
関数でそれをラップするのに十分簡単:function prepend() { while read line; do echo "${1}${line}"; done; }
tzrlk

46

これを試して:

cmd | awk '{print "[ERROR] " $0}'

乾杯


1
これには、式全体が単一引用符で囲まれている必要があるため、「[ERROR]」を変数にできないという欠点があります。
user1071136

4
awk -vT="[ERROR] " '{ print T $0 }'またはawk -vT="[ERROR]" '{ print T " " $0 }'
Tino 14

2
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'またはT="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
ティノ14

引用符のスコープを終了して変数を逆参照することができます。- cmd | awk '{print "['$V]' " $0}'これは開始時に一度評価されるため、パフォーマンスのオーバーヘッドはありません。
ロバート

13

@grawityの功績により、彼のコメントを回答として提出しています。

sed 's/^/[ERROR] /' cmd

なぜこれがbashソリューションよりも望ましいのですか?
user14645

1
私はあなたの目的に依存すると思います。ファイルのすべての行に単純に追加することが目的であれば、非常に使い慣れたツールを使用して、ごくわずかな文字でその目的を達成します。私は10行のbashスクリプトよりもはるかにそれを好みます。awkワンライナーが素敵十分ですが、私はより多くの人が精通していることを考えるsedよりawk。bashスクリプトは何をするのにも適していますが、尋ねられていない質問に答えているようです。
エリックウィルソン

pjzが提出した答えもまた素晴らしいワンライナーです。追加のプログラムやプロセスはなく、少し速く実行できます。
user14645

3
sed X cmd読み取りcmdを実行しません。どちらかcmd | sed 's/^/[ERROR] /'またはsed 's/^/[ERROR] /' <(cmd)cmd > >(sed 's/^/[ERROR] /')。ただし、後者には注意してください。これは、あなたがの戻り値にアクセスすることを可能にしてもいること、それはおそらくあなたが出力を見ているので、バックグラウンドで実行した後、 cmdを完成。ただし、ファイルへのログインには適しています。そして、おそらくより速いことに注意してください。cmdsedawksed
ティノ14

いいね このコマンドは簡単にエイリアスされます。 alias lpad="sed 's/^/ /'"。エラーの代わりに、先頭に4つのスペースを挿入します。さて、マジックのトリック: ls | lpad | pbcopyとして4つのスペースマーク、それをしてLSの出力を付加しますマークダウンのためのコードを使用すると、(クリップボードを貼り付けることを意味し、pbcopyが直接にStackOverflowまたはその他の値下げコンテキストにMac上で、それをつかみます)。(最初の試行で)awkの答えができなかっaliasたので、これが勝ちです。 しばらく読み取りソリューションは、別名-できますが、私は、これは見つけるのsedより表現。
JLペイレット

8

速度テストを行うためにGitHubリポジトリを作成しました。

結果は次のとおりです。

  • 一般的な場合、awkは最速です。 sedは少し遅く、より遅くperlはありませんsed。どうやら、これらはすべてテキスト処理用に高度に最適化された言語です。
  • フォークが支配的な非常に特殊な状況では、スクリプトをコンパイル済みkshスクリプト(shcomp)として実行すると、処理時間をさらに節約できます。対照的に、bashコンパイルされたkshスクリプトと比較して非常に遅いです。
  • 静的にリンクされたバイナリを作成して作成するawkことは、努力する価値がないと思われます。

対照的にpython、非常に遅いですが、コンパイルされたケースはテストしていません。これは、通常、このようなスクリプトケースで行うことではないからです。

次のバリアントがテストされます。

while read line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST]" $line; done
while read -r line; do echo "[TEST]" "$line"; done
sed 's/^/[TEST] /'
awk '{ print "[TEST] " $0 }'
awk -vT="[TEST] " '{ print T $0 }'
awk -vT="[TEST]" '{ print T " " $0 }'
awk -vT="[TEST]" 'BEGIN { T=T " "; } { print T $0 }'
T="[TEST] " awk '{ print ENVIRON["T"] $0 }'
T="[TEST]" awk '{ print ENVIRON["T"] " " $0 }'
T="[TEST]" awk 'BEGIN { T=ENVIRON["T"] " " } { print T $0 }'
perl -ne 'print "[TEST] $_"'

私のツールの1つの2つのバイナリバリアント(ただし、速度は最適化されていません):

./unbuffered.dynamic -cp'[TEST] ' -q ''
./unbuffered.static -cp'[TEST] ' -q ''

Pythonバッファリング:

python -uSc 'import sys
for line in sys.stdin: print "[TEST]",line,'

そして、バッファなしのPython:

python -uSc 'import sys
while 1:
 line = sys.stdin.readline()
 if not line: break
 print "[TEST]",line,'

awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'出力にタイムスタンプ
ティノ


3

stdoutとstderrを処理するソリューションが必要だったので、書きprepend.sh、それを自分のパスに入れました。

#!/bin/bash

prepend_lines(){
  local prepended=$1
  while read line; do
    echo "$prepended" "$line"
  done
}

tag=$1

shift

"$@" > >(prepend_lines "$tag") 2> >(prepend_lines "$tag" 1>&2)

これでprepend.sh "[ERROR]" cmd ...、を実行して、の出力に「[ERROR]」を追加することができますがcmd、まだstderrとstdoutは分離されています。


私はこのアプローチを試みましたが、これらの>(サブシェルでは、解決できなかった何かが進行していました。スクリプトが完了しているように見え、プロンプトが戻った後に出力が端末に到着しているようで、少し面倒でした。最終的にここで答えを
見つけ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.