UNIXシェルスクリプトのリストから一意または個別の値を選択する
質問
改行で区切られた長い値のリストを返すkshスクリプトがあり、一意/個別の値のみを表示したい。これを行うことは可能ですか?
たとえば、私の出力がディレクトリ内のファイルサフィックスであるとします:
tar gz java gz java tar class class
次のようなリストを見たい:
tar gz java class
解決
uniq
および sort
アプリケーションをご覧ください。
./yourscript.ksh | sort | uniq
(FYI、はい、このコマンドラインではソートが必要です。 uniq
は、直後にある重複行のみを削除します)
編集:
Aaron Digulla と uniq
のコマンドラインオプションの関係:
次の入力を与えます:
class jar jar jar bin bin java
uniq
はすべての行を一度だけ出力します:
class jar bin java
uniq -d
は、2回以上現れるすべての行を出力し、1回印刷します。
jar bin
uniq -u
は、一度だけ表示されるすべての行を出力し、一度だけ出力します。
class java
他のヒント
ソートが望ましくない可能性のある大きなデータセットの場合は、次のperlスクリプトも使用できます。
./yourscript.ksh | perl -ne 'if (!defined $x{ソートが望ましくない可能性のある大きなデータセットの場合は、次のperlスクリプトも使用できます。
<*>
これは基本的にすべての行出力を記憶するだけなので、再び出力されることはありません。
これは&quot; sort | uniq
&quot;事前に並べ替えが必要ないという点でソリューション。
}) { print ソートが望ましくない可能性のある大きなデータセットの場合は、次のperlスクリプトも使用できます。
<*>
これは基本的にすべての行出力を記憶するだけなので、再び出力されることはありません。
これは&quot; sort | uniq
&quot;事前に並べ替えが必要ないという点でソリューション。
; $x{ソートが望ましくない可能性のある大きなデータセットの場合は、次のperlスクリプトも使用できます。
<*>
これは基本的にすべての行出力を記憶するだけなので、再び出力されることはありません。
これは&quot; sort | uniq
&quot;事前に並べ替えが必要ないという点でソリューション。
} = 1; }'
これは基本的にすべての行出力を記憶するだけなので、再び出力されることはありません。
これは&quot; sort | uniq
&quot;事前に並べ替えが必要ないという点でソリューション。
zsh を使用すると、次のことができます。
zsh-5.0.0[t]% cat infile
tar
more than one word
gz
java
gz
java
tar
class
class
zsh-5.0.0[t]% print -l "${(fu)$(<infile)}"
tar
more than one word
gz
java
class
またはAWKを使用できます:
zsh-4.3.9[t]% awk '!_[<*>]++' infile
tar
more than one word
gz
java
class
sort
および uniq
にパイプします。これにより、すべての重複が削除されます。
uniq -d
は重複のみを提供し、 uniq -u
は一意のもののみを提供します(重複を削除します)。
AWKを使用すると、ソートよりも高速に処理できます
./yourscript.ksh | awk '!a[<*>]++'
要求に応じて一意(ただし、並べ替えなし);
〜70未満の要素に対して使用するシステムリソースが少なくなります(時間をかけてテストした場合);
stdinからの入力を受け取るように書かれている、
(または変更して別のスクリプトに含める):
(バッシュ)
bag2set () {
# Reduce a_bag to a_set.
local -i i j n=${#a_bag[@]}
for ((i=0; i < n; i++)); do
if [[ -n ${a_bag[i]} ]]; then
a_set[i]=${a_bag[i]}
a_bag[i]=\0'
for ((j=i+1; j < n; j++)); do
[[ ${a_set[i]} == ${a_bag[j]} ]] && a_bag[j]=\0'
done
fi
done
}
declare -a a_bag=() a_set=()
stdin="$(</dev/stdin)"
declare -i i=0
for e in $stdin; do
a_bag[i]=$e
i=$i+1
done
bag2set
echo "${a_set[@]}"