私のファイルには、学生と教師の2つのフィールドがあります。セミコロンで区切られており、どの学生に2人の異なる教師がいるかを探しています。
jdoe;ateacher
jdoe;bteacher
jsmith;cteacher
bbrown;dteacher
dholden;eteacher
次のアドレスに送信されます。
jdoe;ateacher
jdoe;bteacher
シェルでどうすればいいですか?
メモ:これは宿題です。正確な答えを探しているのではなく、どこから始めるべきかわかりません。ファイルから必要なフィールドに解析して転送しました。今、重複する項目を見つけるだけですが、始める方法がわかりません。
答え1
表示するファイル形式が厳しく、生徒に2人の教師がいる場合は、生徒が2回だけ表示され、特定の生徒のエントリが常に隣にあると仮定すると、このコマンドを使用してすべての重複エントリを見つけることができます。このファイルの重複は、生徒に教師が何人かいることを示しているため、これを無視できます。
はい
$ awk -F';' '{ print $1 }' file | uniq -d
jdoe
その後、ファイルは解析され、フィールド区切りスイッチをfile
使用してawk
分割されます-F';'
。次に、awk
生徒の名前である最初のフィールドのみを印刷するように指示します。次に、その出力をパイプし、重複しuniq
た行だけを印刷するように指示します。
その後、forループでこの情報を使用し、上記のコマンドで返されたリストに生徒を含む行のみを印刷できます。ループのおおよその構造は次のとおりです。
$ for i in $(..cmd from above..); do
... print lines that contain "$i" ...
done
ここでは、初期コマンドの出力を取得し、awk
Bashシェルのforループを使用して繰り返します。これは通常、ほとんどの人が初めて起動したときに取るアプローチです。
はい
$ for i in $(awk -F';' '{ print $1 }' file | uniq -d); do \
grep "^$i;" file; done
jdoe;ateacher
jdoe;bteacher
この方法は効果的ですが、いくつかの問題もあります。ファイル名にスペースが含まれていると、この方法は失敗します。 whileループを使用してより複雑なアプローチに切り替えることができます。
$ while read; do grep "^$i;" file; done \
< <(awk -F';' '{ print $1 }' file | uniq -d)
jdoe;ateacher
jdoe;bteacher
ここではコマンドの出力を取得し、次のようにwhileループに渡します。
$ while read; do .... ; done < <(...our command...)
これの利点は、この表記法を使用して一時ファイルを作成し、すべての結果をwhileループに行として渡すことができることです。したがって、このread
コマンドはforループの実装では、空白ではなく改行区切りの結果のみを解析します。
< <(...command...)
はい
forループとスペースを使用すると、次のことが起こります。
$ for i in jdoe john smith jjill;do echo "$i"; done
jdoe
john
smith
jjill