2016-07-09 6 views
1

私はzshからbashに切り替える過程にあり、エントリを並べ替えることなく$PATHの重複したエントリを削除できるbashスクリプトを生成する必要があります(したがって、sort -dの魔法はありません)。 zshには、これを効率的に行うための素敵な配列処理ショートカットがありますが、私はbashのそのようなショートカットを認識していません。私はthis answerに出くわしましたが、そこには90%の方法がありましたが、私がよく理解したい小さな問題があります。そのawkコマンドを実行すると、正しく処理された最後のレコードがパターンに一致するように見えます。awkパターンは常に最後のレコードに一致しますか?

$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc" 
aa:bb:cc:cc 
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb" 
aa:bb:cc:bb 
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:" # note trailing colon 
aa:bb:cc: 

私はawkのそれがこのように動作理由を知るために十分理解していないが、私はそうのような中間アレイを使用することで問題を回避するために管理しています。

array=($(awk 'BEGIN{RS=":";ORS=" "}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:")) 
# Use a subshell to avoid modifying $IFS in current context 
echo $(export IFS=":"; echo "${array[*]}") 
aa:bb:cc 

これは、しかし、サブ最適な解決策のように思えるので、私の質問です:私は処理し、最終的な記録に偽陽性の一致を引き起こしているawkコマンドで間違った何かをしましたか?

答えて

4

元の文字列の最後のレコードは、で、ccとは異なります。ときにわからないどのような任意の言語で任意のプログラムの中で起こっている、いくつかのprint文を追加すると、デバッグ/調査にステップ1:あなたはRSが:または\nになりたい場合は、単に(GNU awkを持つ少なくとも旨を

$ awk 'BEGIN{RS=ORS=":"} {print "<"$0">"}' <<<"aa:bb:cc:aa:bb:cc" 
<aa>:<bb>:<cc>:<aa>:<bb>:<cc 
>:$ 

):

$ awk 'BEGIN{RS="[:\n]"; ORS=":"} !a[$0]++' <<<"aa:bb:cc:aa:bb:cc" 
aa:bb:cc:$ 

上記のすべての$は私のプロンプトです。

+0

良い例。しかし、なぜ新しい行が文字列に追加されたのか説明できますか? –

+2

これはbashがやっていることです。それは 'cmd <<<" string "'が '' echo "string"と同じように動作するようにします。 cmd'を実行しますが、余分なコマンド( 'echo')とパイプは使用しません。 POSIXテキスト処理ツール(sed、awk、grepなど)は、POSIXテキストファイルでのみ動作することが保証されています。そうしないと未定義の動作が発生するため、ファイルや入力ストリームが改行で終わらない場合はPOSIXテキストファイル/ストリームを使用して、期待された/望ましい動作を生み出すために後続の改行が必要です。 –

+1

ありがとうございます!私は今問題がなぜ発生するのかをよりよく理解しているので、問題の適切な解決策を作ることができます。このような小さな問題があったとしても、あなたの答えは私にとって非常に役に立ちました。 – Christopher

0

何が起こっているかを確認するもう一つの可能​​な回避策の代わりに、あなたのbashアレイソリューション

$ echo "aa:bb:cc:aa:bb:cc" | tr ':' '\n' | awk '!a[$0]++' | paste -sd: 
aa:bb:cc 
関連する問題