bashの文字列/配列から一意の要素の配列を作成するにはどうすればよいですか?


8

文字列「1 2 3 2 1」または配列[1,2,3,2,1]がある場合、どのようにして一意の値を選択できますか。

"1 2 3 2 1" produces "1 2 3" 

または

[1,2,3,2,1] produces [1,2,3]

uniqに似ていますが、uniqは行内のパターンではなく、行全体で機能するようです...

回答:


4

GNUの場合awk(これも元の順序を保持します)

printf '%s\n' "1 2 3 2 1" | awk -v RS='[[:space:]]+' '!a[$0]++{printf "%s%s", $0, RT}'
1 2 3 

readへのbash配列

read -ra arr<<<$(printf '%s\n' "1 2 3 2 1" |
 awk -v RS='[[:space:]]+' '!a[$0]++{printf "%s%s", $0, RT}')
printf "%s\n"  "${arr[@]}"
1
2
3

どうすれば配列を作成できますか?
Michael Durrant 2014年

@MichaelDurrant、bash配列を意味する場合、方法を追加
iruvar

アレイに空白が含まれている場合は、こちらをご覧ください
Tom Hale

@iruvarこれが実際に何を意味するのか説明してくれませんか?私はawkスクリプトを初めて使用するので、これを言ったときに実際に何が起こるかを明確にできると助かります!a [$ 0] ++
Abhishek

@iruvar上記の構文を説明するWebサイトをコメントで説明できない場合は、少なくとも有益です。
Abhishek

9

zshを使用している場合:

$ array=(1 2 3 2 1)
$ echo ${(u)array[@]}
1 2 3

または(KSH_ARRAYSオプションが設定されていない場合)

$ echo ${(u)array}
1 2 3

1
配列に空の要素が含まれている可能性がある場合は、"${(u)array[@]}"またはを使用する必要があります"${(@u)array}"(引用符に注意してください)。
ステファンChazelas

私はzsh 5.1.1(x86_64-ubuntu-linux-gnu)を使用しており${(u)array}、引用符なしで配列が空または空の文字列が含まれている場合でも機能します。
kiamlaluno 2017

4

任意の値を持つ配列の場合、bash組み込みの演算子がないため、非常に扱いにくいです。

bash ただし、変数にNUL文字を格納することはサポートされていないため、それを利用して他のコマンドに渡すことができます。

に相当zsh

new_array=("${(@u}array}")

最近のGNUシステムでは、次のようになります。

eval "new_array=($(
  printf "%s\0" "${array[@]}" |
    LC_ALL=C sort -zu |
    xargs -r0 bash -c 'printf "%q\n" "$@"' sh
  ))"

または、の最新バージョンではbash、空の配列要素がないと仮定して、連想配列を使用できます。

unset hash
typeset -A hash
for i in "${array[@]}"; do
  hash[$i]=
done
new_array=("${!hash[@]}")

bash 4.4以降とGNUの場合sort

readarray -td '' new_array < <(
  printf '%s\0' "${array[@]}" | LC_ALL=C sort -zu)

要素の順序は、これらの異なるソリューションでは同じではありません。

tcsh

set -f new_array = ($array:q)

保持なるF(IRST要素a b a=> a b)などzsh(u)拡張フラグ。

set -l new_array = ($array:q)

最後を保持します(a b a=> b a)。ただし、これらは配列から空の要素を削除します。


1

この解決策は私にとってうまくいきました。

ids=(1 2 3 2 1)
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '

上記は1 2 3を出力として生成します。

Costasによって提案された短いバージョンは、

printf "%s\n" "${ids[@]}" | sort -u | tr '\n' ' '

最終結果を配列に格納するには、次のようにします。

IFS=$' '
arr=($(printf "%s\n" "${ids[@]}" | sort -u | tr '\n' ' '))
unset IFS

さて、エコーをオンにするとarr、これが私の出力です。

echo "${arr[@]}"
1 2 3

参考文献

https://stackoverflow.com/a/13648438/1742825 https://stackoverflow.com/a/9449633/1742825


@Costas、ありがとう。私はそれを答えに組み込んだ。
Ramesh 2014年

最終結果を配列にするにはどうすればよいですか?
Michael Durrant 2014年

@MichaelDurrant、更新された回答を見て、これで問題ないかどうか私に知らせてください。
Ramesh 2014年

結果を配列に入れたい場合は、最後のコマンドを削除できますtr '\n' ' '
Costas

0

それを完全にシェルで行い、結果を配列に入れるには、

declare -A seen
for word in one two three two one
do
        if [ ! "${seen[$word]}" ]
        then
                result+=("$word")
                seen[$word]=1
        fi
done
echo "${result[@]}"

つまり、特定の単語をまだ表示していない場合は、その単語をresult配列に追加して、表示済みとしてフラグを付けます。単語が表示されたら、それ以降の出現は無視してください。


2
unset seen以前declare -A seen$seen(環境からのスカラー変数としても)定義されている場合は、以前に必要になることに注意してください。
ステファンChazelas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.