Jet*_*tse 75 linux arrays bash unique
我和这里的问题差不多.
我有一个包含aa ab aa ac aa ad
等的数组.现在我想从这个数组中选择所有独特的元素.认为,这将是简单的用sort | uniq
或sort -u
因为他们在其他问题中提到,但没有在数组中改变...的代码是:
echo `echo "${ids[@]}" | sort | uniq`
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
sam*_*hen 111
有点hacky,但这应该这样做:
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Run Code Online (Sandbox Code Playgroud)
要将排序的唯一结果保存回数组,请执行数组赋值:
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
Run Code Online (Sandbox Code Playgroud)
如果你的shell支持herestrings(bash
应该),你可以echo
通过将其改为:
tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '
Run Code Online (Sandbox Code Playgroud)
输入:
ids=(aa ab aa ac aa ad)
Run Code Online (Sandbox Code Playgroud)
输出:
aa ab ac ad
Run Code Online (Sandbox Code Playgroud)
说明:
"${ids[@]}"
- 用于处理shell数组的语法,无论是作为一部分echo
还是作为herestring使用.该@
部分意味着"数组中的所有元素"tr ' ' '\n'
- 将所有空格转换为换行符.因为你的数组被shell看作一行上的元素,用空格分隔; 因为sort要求输入在不同的行上.sort -u
- 排序并保留唯一的元素tr '\n' ' '
- 将我们之前添加的换行符转换回空格.$(...)
- 指挥替代tr ' ' '\n' <<< "${ids[@]}"
是一种更有效的方式:echo "${ids[@]}" | tr ' ' '\n'
gho*_*oti 22
如果您正在运行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
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为在数组中,每个键只能出现一次.当for
循环到达aa
in 的第二个值时a[2]
,它将覆盖b[aa]
最初设置的值a[0]
.
在本地的bash做的事情可以比使用管道和外部工具,如更快的sort
和uniq
.
如果你有信心,你可以for
通过使用printf
能够为多个参数回收其格式来避免循环,尽管这似乎需要eval
.(如果你没事的话,现在就停止阅读.)
$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") )
$ declare -p b
declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
Run Code Online (Sandbox Code Playgroud)
此解决方案需要的原因eval
是在分词之前确定了数组值.这意味着命令替换的输出被认为是单个字而不是一组键=值对.
虽然这使用子shell,但它仅使用bash builtins来处理数组值.务必评估您对eval
批判性眼睛的使用.如果您不是100%确信chepner或glenn jackman或greycat会发现您的代码没有错误,请改用for循环.
das*_*one 12
我意识到这已经得到了回答,但它在搜索结果中显得非常高,并且它可能对某人有所帮助.
printf "%s\n" "${IDS[@]}" | sort -u
Run Code Online (Sandbox Code Playgroud)
例:
~> 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
~>
Run Code Online (Sandbox Code Playgroud)
von*_*app 11
如果你的数组元素有空格或任何其他shell特殊字符(并且你能确定它们不是吗?)那么首先捕获它们(你应该总是这样做)用双引号表达你的数组!例如"${a[@]}"
.Bash将字面上解释为"单独参数中的每个数组元素".在bash中,这总是很有效.
然后,为了得到一个已排序(和唯一)的数组,我们必须将它转换为格式排序理解并能够将其转换回bash数组元素.这是我提出的最好的:
eval a=($(printf "%q\n" "${a[@]}" | sort -u))
Run Code Online (Sandbox Code Playgroud)
不幸的是,这在空数组的特殊情况下失败,将空数组转换为1个空元素的数组(因为printf有0个参数,但仍然打印好像它有一个空参数 - 参见解释).所以你必须在if或者什么东西中捕获它.
说明:printf"shell的%q格式转义"打印的参数,就像bash可以像eval这样恢复一样!因为每个元素都是在自己的行上打印转义的,所以元素之间的唯一分隔符是换行符,并且数组赋值将每行作为元素,将转义的值解析为文本文本.
例如
> a=("foo bar" baz)
> printf "%q\n" "${a[@]}"
'foo bar'
baz
> printf "%q\n"
''
Run Code Online (Sandbox Code Playgroud)
eval是必要的,可以去掉每个返回数组的值.
要创建由唯一值组成的新数组,请确保数组不为空,然后执行以下操作之一:
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | sort -u)
Run Code Online (Sandbox Code Playgroud)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | awk '!x[$0]++')
Run Code Online (Sandbox Code Playgroud)
警告:不要尝试做类似的事情NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) )
。它会在空格上破裂。
小智 8
'sort'可用于命令for循环的输出:
for i in ${ids[@]}; do echo $i; done | sort
Run Code Online (Sandbox Code Playgroud)
并使用"-u"消除重复:
for i in ${ids[@]}; do echo $i; done | sort -u
Run Code Online (Sandbox Code Playgroud)
最后,您可以使用唯一元素覆盖您的数组:
ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` )
Run Code Online (Sandbox Code Playgroud)
这也将保持秩序:
echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'
Run Code Online (Sandbox Code Playgroud)
并使用唯一值修改原始数组:
ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'))
Run Code Online (Sandbox Code Playgroud)
在不丢失原始顺序的情况下:
uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' '))
Run Code Online (Sandbox Code Playgroud)
猫号.txt
1 2 3 4 4 3 2 5 6
Run Code Online (Sandbox Code Playgroud)
将行打印到列中:
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}'
1
2
3
4
4
3
2
5
6
Run Code Online (Sandbox Code Playgroud)
查找重复记录:
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk 'x[$0]++'
4
3
2
Run Code Online (Sandbox Code Playgroud)
替换重复记录:
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk '!x[$0]++'
1
2
3
4
5
6
Run Code Online (Sandbox Code Playgroud)
仅查找 Uniq 记录:
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i|"sort|uniq -u"}
1
5
6
Run Code Online (Sandbox Code Playgroud)
如果您想要一个仅使用 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
Run Code Online (Sandbox Code Playgroud)
这将输出
bar
foo
bar none
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
73181 次 |
最近记录: |