2017-09-18 7 views
1

シェルスクリプトでは非常に新しいので、次の作業に問題があります。file1でも見つかった行をfile2から抽出し、新しいファイル3へ。私は(私はそれが基本的なgrepコマンドで動作します知っているが、私はループを備えた方法を見つける必要がある)File2のループを使用してfile1に存在するfile1の行を抽出します

はFile1

John 5 red books 
Ashley 4 yellow music 
Susan 8 green films 

John 
Susan 
このため、ループを使用させていただいておりますFILE3ため

所望の出力は次のようになります

John 5 red books 
Susan 8 green films 

所望の出力は、bashスクリプトとループを使用して見つけなければなりません。私は、次のループを試してみましたが、私はこれを使って、結果にはいくつかの行をしないのです:

while read line 
do 
grep "${line}" $file1 
done < $file2 >> file3.txt 

誰もが私のスクリプトを改善する方法上の任意の考えや(再びループを使用して)任意の新しいアイデアを持っている場合、それは次のようになり大いに感謝します。ありがとうございました!

+0

すでにgrepを使っているので、 'man grep'を読んで' grep -Ff file2 file1'を試してください。 'while'ループは必要ありません。 'grep'のいくつかのバージョンはそのオプションをサポートしていないので、' fgrep -f file2 file1'を試してください。また、 'fgrep'の中には、' -f'引数(おそらくは2Kという小さなもの)に使うことができるファイルのサイズを制限しているものもあります。がんばろう。 – shellter

+0

あなたのご意見ありがとうございます。ループでこれを行う方法はありますか(たとえgrepを除外することを意味するとしても)。私の割り当ては、これを解決するためのループの使用を特に求めているので、私はそれを回避しようとしています。再度、感謝します! – Pablita

+0

なぜ制約がありますか?標準の 'join'ユーティリティを使用できない理由はありますか? –

答えて

1

Bashを使用しているので、File2から連想配列を作成し、これを使用してメンバーシップをチェックできます。以下のようなもの(未テスト):AWKで

read -a names <File2 
local -A n 
for i in "${names[@])" 
do n["$i"]="$i" 
done 

while read name rest 
do [ "${n[$name]}" ] && echo "$name $rest" 
done <File1 >file3 
0

Awkのソリューション:

awk 'NR==FNR{ arr[$0]="";next } { for (i in arr) { if (i == $1) { print $0 } } }' file2 file1 

まず、我々はFILE2のデータとの配列を作成します。これを使用して、スペース区切りの最初のデータをチェックし、一致するものがあれば印刷します。

+0

これは[my answer](https://stackoverflow.com/a/46287619/519360)と[George Vasiliouの回答](https://stackoverflow.com/a/46286035/519360)と同じロジックですが、余分なネストされたループは、2番目のファイルの1行につき1回実行されます。 –

0

ます。grepで

$ awk 'NR==FNR{ a[$1];next } $1 in a' file2 file1` 

$ grep -F -f file2 file1 
1

ここでループは良い教育運動ですが、それはこのために理想的ではありません現実の世界。

技術的には、このawkのソリューションは、動作し、ループを使用していますが、私はそれはあなたのインストラクターが探しているものではありません推測している:(NRレコードの「数ある

awk 'NR == FNR { seen[$1]=1; next } seen[$1]' File1 File2 

これは、最初のファイルをループ現在のファイルのレコード数であるので、最初の句は同じ値である必要があるため、最初の入力ファイルでのみ起動することができ、ハッシュ(データ(キー/値のペアを持つ構造体、連想配列または辞書)キーが最初の列の値($1)であるので、後でそれを抽出することができます。 psその入力行の後のスタンザ。

コードが2番目のファイルをループするとき、最初の句は起動せず、入力の最初の列はseenのハッシュで参照されます。存在する場合、その値は1であり、それはtrueと評価されるため、値を出力します。


ハッシングは間違いなく最も最適な計算アプローチである(ノーアクションで句は{ print }を意味します)。それ以外のものは大規模に高価です。ここでは、ハッシュと同じ基本概念を使用するが、技術的にはハッシュしないソリューションがあります。ソートとファイルの読み込みの仕組みによって、暗黙のループが含まれています。 (ラッピングを防止するために、私は積極的に空白が崩壊しました。print $1の代わりに、例えばprint$1を与えた場合$はすでに先頭にスペースを意味特殊文字であるため、AWKは文句はありません。)

{awk '{print$1}' File1 |sort -u; awk '{print$1}' File2 |sort -u;} |sort |uniq -d 

これにより、File1とFile2が別々にソートされ、各ファイル内の重複したエントリが削除されます(重複するエントリがないことがわかっている場合はsort File1 File2を実行してから、uniq -dに重複する行のみを表示できるように全体をソートします)。


は組み込みコマンドとネイティブのbash答えをToby Speight's answerを参照してください。それはループとハッシュを使用します。

+0

徹底的な説明に感謝します! :) – Pablita

+1

私はあなたがStackOverflowの初心者だと思う。感謝はあなたが渡した+ 1によって定量化されます。これまでのところ、私は任意の答えに+1を与えました(Toby's、実際)。それぞれの回答に+1を付けることをお勧めします(義務はありません)。あなたの質問を解決する答えがある場合は、それを受け入れる必要があります(その評価の下にあるチェックマークをクリックしてください)。これらは評判スコアに影響します。 –

関連する問題