2016-04-03 12 views
3

私はこの関数を作成して、ファイルのすべての行に複数のgrepを作成します。私は、次のようにそれを実行します。string1string2、...、stringNこのbash関数で "for"ループの使用を避けるにはどうすればよいですか?

cat file.txt | agrep string1 string2 ... stringN 

function agrep() { 
    for a in [email protected]; do 
    cmd+=" | grep '$a'"; 
    done ; 
    while read line ; do 
    eval "echo "\'"$line"\'" $cmd"; 
    done; 
} 

アイデアは、すべての文字列を含むすべての行を印刷することです。これは、すでに動作しますが、私は表現構築するforの使用を避けたい:

| grep string1 | grep string2 ... | stringN 

そしてそれはまた、evalの利用が可能です場合を。

echo "| grep $"{1..3} 

をそして私が手::次のように私はいくつかの拡張を作ってみました

| grep $1 | grep $2 | grep $3 

これは私が欲しいものはほとんどですが、問題は私がしようとしたときということです:

echo "| grep $"{1..$#} 

bash cantは$#のために{1..$#}を展開できないため、拡張は行われません。それは数字だけで動作します。 agrep機能でforの使用を避けるために機能する拡張機能を構築したいと思います。

答えて

5
agrep() { 
    if [ $# = 0 ]; then 
     cat 
    else 
     pattern="$1" 
     shift 
     grep -e "$pattern" | agrep "[email protected]" 
    fi 
} 
+0

これは非常に便利でしたが、私は1つの質問があります。if文はオプションです。それの使用について確かめてください。 – neo33

+0

引数がまったく指定されていない場合、またはすべての引数が削除された後、 'agrep'はその入力を変更せずにそのまま出力に渡す必要があります。 'cat'コマンドはそれを行います。 –

+0

ご協力ありがとうございます、これは非常に便利でした。 – neo33

2

awkレスキュー!

あなたが複数のgrepの呼び出しを回避し

awk -v pat='string1 string2 string3' 'BEGIN{n=split(pat,p)} 
       {for(i=1;i<=n;i++) if($0!~p[i]) next}1 ' file 

をawkにするために切り替えることにより、コマンドを構築することができますが、上記の例のように、あなたのスペースで区切られた文字列を入力してください。代わりにちょうどstring2ためgrepなどにこれを行う1つの方法はagrep再帰を作るであることを、パイプ、その後、string1に一致するすべての行を取得し、各ライン上の各複数のgrep Sを実行しているの

+1

一致するパターンによっては、すべてを1つの区切り文字列にパックする方法を見つけるのは難しいかもしれません。 (文字列の1つに空白などが含まれているとしたらどうでしょう?) – chepner

+0

空白で区切られている必要はありません(元の例を模倣しています)ので、未使用の文字を区切り文字として選択できます。 – karakfa

+0

一般的には、未使用の文字が*あるかどうか、または未使用のものが何かを事前に知っていることは保証できません。これは解決のために配列が導入されたのと同じ問題です。 – chepner

3

agrep() { 
    if (($# == 0)); then 
     cat # With no arguments, just output everything 
    else 
     grep "$1" | agrep "${@:2}" 
    fi 
} 

これは最も効率的な解決策ではありませんが、簡単です。

は(これのPOSIX準拠のバージョンである、Rob Mayoff's answerをメモしておいてください。)

2

ないコマンドの文字列を構築間違いなく優れている(chepner'sRob Mayoff'sの回答を参照してください)。しかし、単なる一例として、あなたはprintfを使用してforを避けることができます。

agrep() { 
    cmd=$(printf ' | grep %q' "[email protected]") 
    sh -c "cat $cmd" 
} 

printfを使用してもパターンの特殊文字を多少役立ちます。 help printfから:

In addition to the standard format specifications described in printf(1), 
printf interprets: 

    %b expand backslash escape sequences in the corresponding argument 
    %q quote the argument in a way that can be reused as shell input 
    %(fmt)T output the date-time string resulting from using FMT as a format 
     string for strftime(3) 

%qの目的は、シェルの入力に適した出力を提供しているので、これは安全でなければなりません。

また、[email protected]というだけでなく、ほとんどの場合、引用符付きの"[email protected]"を使用することがほとんどです。

+1

@ mklement0ありがとう、はい、それは本当です。 – muru

関連する問題