Bashのユーティリティプログラムへの連鎖呼び出しをパラメーター化する


12

Bdinシェルで使用されるブラックボックスUNIXプログラムがあり、stdinからデータの列を読み取り、それらを処理して(平滑化効果を適用して)、stdoutに出力します。UNIXパイプで使用します。たとえば

generate | smooth | plot  

よりスムーズにするために、スムーズを繰り返すことができるので、Bashコマンドラインから次のように呼び出されます。

generate | smooth | smooth | plot   

あるいは

generate | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | plot

これは厄介です。私は、Bashラッパーを作成して、smoothその出力をsmooth任意の回数の新しいインスタンスにパイプで送り、新しいインスタンスに戻すことができるようにします

generate | newsmooth 5 | plot

の代わりに

generate | smooth | smooth | smooth | smooth | smooth | plot

私の最初の試みは、現在のディレクトリに一時ファイルを生成して削除するBashスクリプトでしたが、書き込みアクセスのあるディレクトリにいなかった場合は見苦しくなり、中断するとガベージファイルが残りました。

smoothプログラムへの引数はありません。

そのようなプログラムを「ラップ」して呼び出し回数をパラメータ化するよりエレガントな方法はありますか?


1
私はあなたの例では、質問のために強制ケースではなく、実際の必要性を願う
arielnmz

回答:


18

再帰関数でラップすることができます:

smooth() {
  if [[ $1 -gt 1 ]]; then # add another call to function
    command smooth | smooth $(($1 - 1)) 
  else
    command smooth # no further 
  fi
}

これを次のように使用します

generate | smooth 5 | plot

これは次と同等です

generate | smooth | smooth | smooth | smooth | smooth | plot

これは完璧で、必要に応じて正確に動作します。そして今、bashの「コマンド」キーワードについて学びました。
ダイアンウィルボール


5

必要なsmoothコマンドの数と同じ数のコンマを入力する余裕がある場合は、シェルのコンマ区切りのブレース展開を利用できます。

TL; DR

サンプルケースのコマンドライン全体は次のようになります。

generate | eval 'smooth |'{,,,,} plot

注意:

  • 繰り返しの回数を増やしたり減らしたりする場合は、カンマを追加または削除します smooth |
  • それはブレース展開によって生成された最後の文字列に含まれているため、|前にありませんplotsmooth |
  • またsmooth、開き括弧の前にある引用符で囲まれた固定部分内に正しく含めることができる限り、に引数を提供することもできます。いずれにしても、コマンドのすべての繰り返しにそれらを提供することに注意してください

使い方

コンマ区切りのブレース拡張を使用すると、指定した固定部分と指定した可変部分で構成される文字列を動的に生成できます。producesのように、指定された変数部分と同じ数の文字列をa{b,c,d}生成しab ac adます。

ここでの小さなコツは、空の変数部分のリストを作成する場合、つまりブレース内にコンマのみを含めると、ブレース展開は固定部分のコピーのみを生成することです。例えば:

smooth{,,,,}

生成されます:

smooth smooth smooth smooth smooth

4つのコンマで5つのsmooth文字列が生成されることに注意してください。それがまさにこのブレース拡張の仕組みです。カンマに1を加えた文字列を生成します。

もちろんあなたの場合は、|それぞれを分離する必要もあるsmoothので、固定部分に追加するだけですが、シェルがすぐに解釈しないように適切に引用するように注意してください。あれは:

'smooth|'{,,,,}

生成されます:

'smooth|' 'smooth|' 'smooth|' 'smooth|' 'smooth|'

常に固定部品を配置するの世話をすぐに、オープンブレースに隣接する間にスペースすなわちない' と{

(固定部分を形成するために、固定部分のシェル変数を展開する必要がある場合は、単一引用符の代わりに二重引用符を使用することもできます。シェルの特殊文字が発生したときに必要な余分なエスケープ二重引用符で囲まれた文字列内)。

この時点で、 eval  、シェルが最終的にパイプラインコマンドとして解釈されるようにするには、その文字列に適用するます。

したがって、すべてをまとめると、サンプルケースのコマンドライン全体は次のようになります。

generate | eval 'smooth |'{,,,,} plot

1
これがコールがパラメータ化されている場所で使用される場合、重大なセキュリティ上の懸念があります。再帰的なbash関数と反復的な「評価」文字列構築に関する私の答えを参照してくださいスタックオーバーフローでオーバー。
チャールズダフィー

1
@CharlesDuffy eval評価するために信頼されていない、非サニタイズされた文字列を提供するとき、つまりリンクしたケースのような「不明な」コンテンツを運ぶ可能性がある変数を使用する場合の暗黙のリスクに関する懸念に完全に同意します。一方でeval、特にプロンプ​​トで使用される場合、コマンドの迅速な「配管」に非常に便利です。たとえば、eval入力は、ユーザーが手動で入力したリテラル文字列のみです人
LL3

すでに他の場所で見たように、あなたはいつでものeval strような大げさで愚かなものに置き換えることができます. /dev/stdin <<<str。これは愚か者に印象を与えるだけでなく、@ CharlesDuffyを背負わせます;-)
pizdelect

1
@ pizdelect、LL3の以前のコメントを注意深くお読みください。バランスが取れており、ニュアンスがあり、賢明です。(実際、私自身の最初のコメントには、あなたが無視しているように見えるニュアンスがありました。「呼び出しがパラメーター化される場合に使用される場合」は重要な違いです。LL3のインスタンスパラメーター化され、安全です)。
チャールズダフィー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.