こことほぼ同じ質問があります。
などを含む配列がありますaa ab aa ac aa ad
。この配列からすべての一意の要素を選択したいと思います。他の質問で述べたように、これは単純であると思いsort | uniq
ましsort -u
たが、配列は何も変更されていません...コードは次のとおりです。
echo `echo "${ids[@]}" | sort | uniq`
私は何を間違っていますか?
少しハックですが、これでうまくいくはずです:
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
並べ替えられた一意の結果を配列に保存するには、配列の割り当てを行います。
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
シェルがヒアストリング ( should) をサポートしている場合は、bash
次のecho
ように変更することでプロセスを節約できます。
tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '
2021 年 8 月 28 日時点のメモ:
ShellCheck wiki 2207によるとread -a
、分割を避けるためにパイプを使用する必要があります。したがって、bash のコマンドは次のようになります。
IFS=" " read -r -a ids <<< "$(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')"
また
IFS=" " read -r -a ids <<< "$(tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' ')"
入力:
ids=(aa ab aa ac aa ad)
出力:
aa ab ac ad
説明:
"${ids[@]}"
- シェル配列を操作するための構文 (一部echo
またはヒアストリングとして使用される場合)。@
部分は「配列内のすべての要素」を意味しますtr ' ' '\n'
- すべてのスペースを改行に変換します。配列は、スペースで区切られた単一行の要素としてシェルに表示されるためです。また、ソートは入力が別々の行にあることを期待しているためです。sort -u
- 一意の要素のみを並べ替えて保持するtr '\n' ' '
- 前に追加した改行をスペースに戻します。$(...)
-コマンド置換tr ' ' '\n' <<< "${ids[@]}"
より効率的な方法です:echo "${ids[@]}" | tr ' ' '\n'
Bash バージョン 4 以降を実行している場合 (最新バージョンの Linux ではこれに該当するはずです)、元の配列の各値を含む新しい連想配列を作成することにより、bash で一意の配列値を取得できます。このようなもの:
$ a=(aa ac aa ad "ac ad")
$ declare -A b
$ for i in "${a[@]}"; do b["$i"]=1; done
$ printf '%s\n' "${!b[@]}"
ac ad
ac
aa
ad
これが機能するのは、任意の配列 (任意の言語の連想配列または従来の配列) では、各キーが 1 回しか表示されないためです。for
ループが in の 2 番目の値に到達すると、元々設定されていたaa
ina[2]
を上書きします。b[aa]
a[0]
ネイティブの bash で処理を行うと、パイプや や などの外部ツールを使用するよりも高速になるsort
可能uniq
性がありますが、大規模なデータセットの場合は、awk、python などのより強力な言語を使用すると、パフォーマンスが向上する可能性があります。
自信がある場合は、複数の引数の形式をリサイクルする の機能をfor
使用してループを回避できますが、これには が必要なようです。(それでもよろしければ、ここで読むのをやめてください。)printf
eval
$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") )
$ declare -p b
declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
このソリューションが必要な理由eval
は、単語分割の前に配列値が決定されるためです。つまり、コマンド置換の出力は、一連のキー=値のペアではなく、1 つの単語と見なされます。
これはサブシェルを使用しますが、bash ビルトインのみを使用して配列値を処理します。eval
の使用を批判的な目で評価してください。chepner、glenn jackman、greycat があなたのコードに間違いを見つけられないという 100% の確信がない場合は、代わりに for ループを使用してください。
これはすでに回答済みですが、検索結果でかなり上位に表示されており、誰かの助けになるかもしれません.
printf "%s\n" "${IDS[@]}" | sort -u
例:
~> IDS=( "aa" "ab" "aa" "ac" "aa" "ad" )
~> echo "${IDS[@]}"
aa ab aa ac aa ad
~>
~> printf "%s\n" "${IDS[@]}" | sort -u
aa
ab
ac
ad
~> UNIQ_IDS=($(printf "%s\n" "${IDS[@]}" | sort -u))
~> echo "${UNIQ_IDS[@]}"
aa ab ac ad
~>
'sort' を使用して、for ループの出力を並べ替えることができます。
for i in ${ids[@]}; do echo $i; done | sort
「-u」を使用して重複を排除します。
for i in ${ids[@]}; do echo $i; done | sort -u
最後に、一意の要素で配列を上書きすることができます:
ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` )
猫番号.txt
1 2 3 4 4 3 2 5 6
行を列に出力:
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}'
1
2
3
4
4
3
2
5
6
重複レコードを見つけます。
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk 'x[$0]++'
4
3
2
重複レコードを置換:
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk '!x[$0]++'
1
2
3
4
5
6
Uniq レコードのみを検索します。
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i|"sort|uniq -u"}
1
5
6
bash 内部のみを使用するソリューションが必要な場合は、値を連想配列のキーとして設定し、キーを抽出できます。
declare -A uniqs
list=(foo bar bar "bar none")
for f in "${list[@]}"; do
uniqs["${f}"]=""
done
for thing in "${!uniqs[@]}"; do
echo "${thing}"
done
これは出力されます
bar
foo
bar none