【问题标题】:Printing multiple iterated arrays in Bash so they alternate在 Bash 中打印多个迭代数组,以便它们交替
【发布时间】:2015-11-08 02:37:57
【问题描述】:

我有 2 个数组,其中 artists 包含音乐艺术家姓名,songs 包含歌曲标题。我想要做的是以交替的方式输出每个,以便我得到array1[1] - array2[1], array1[2] - array2[2]...,或者:

Chelsea Wolfe - Mer Pavement - Embassy Row Black Math Horseman - Torment of the Metals ...

这是我现在所拥有的,并提供了示例数组。实际的数组是回显和处理(使用 grep)curl 命令替换的结果,所以我不确定它们是否包含双引号,但我得到的输出与此处提供的示例相同。 [编辑:这是不正确的。正如我在下面对 John1024 的评论中提到的,我使用的实际数组在每个元素之后都有换行符。]

我知道这是错误的,并且我知道为什么(因为我告诉 Bash “打印 artists 的所有元素然后打印 songs 的所有元素”),我只是不知道解决方案。

artists=("Chelsea Wolfe" "Pavement" "Black Math Horseman" "Marriages" "Chelsea Wolfe")
songs=("Mer" "Embassy Row" "Torment of the Metals" "The Liar" "The Waves have Come")

IFS=$'\n'
for ((i=0;i<"${#artists[@]}";++i));
do
printf "%s\n" "${artists[@]} - ${songs[@]}"
done
[Edit: I removed the useless unassigned `OIFS` variable that was here. See my comment to glenn jackman below.]

以某种方式以我想要的交替方式组合它们是否有意义,然后打印该数组,还是有更简单的解决方案?

【问题讨论】:

  • 注意:您从不分配变量 OIFS,因此您将 IFS 分配给脚本末尾的空字符串(如果这只是一个 sn-p,这可能很重要)
  • 是的,脚本100行左右,这只是一部分。我认为你是对的,我确实忘记分配OIFS。我已经修改了脚本以包含您的建议,因此 IFSOIFS 已被完全删除。

标签: arrays bash for-loop


【解决方案1】:

让我们去掉IFS 命令并对printf 命令做一些小的改动:

artists=("Chelsea Wolfe" "Pavement" "Black Math Horseman" "Marriages" "Chelsea Wolfe")
songs=("Mer" "Embassy Row" "Torment of the Metals" "The Liar" "The Waves have Come")

for ((i=0;i<"${#artists[@]}";++i));
do
    printf "%s - %s\n" "${artists[$i]}" "${songs[$i]}"
done

这会产生输出:

Chelsea Wolfe - Mer
Pavement - Embassy Row
Black Math Horseman - Torment of the Metals
Marriages - The Liar
Chelsea Wolfe - The Waves have Come

备用输出

我们可以通过将 printf 行更改为:

printf "%-20s - %s\n" "${artists[$i]}" "${songs[$i]}"

随着这一变化,输出变为:

Chelsea Wolfe        - Mer
Pavement             - Embassy Row
Black Math Horseman  - Torment of the Metals
Marriages            - The Liar
Chelsea Wolfe        - The Waves have Come

处理带有尾随换行符的数组

根据 cmets,假设元素有尾随换行符:

artists=($'Chelsea Wolfe\n' $'Pavement\n' $'Black Math Horseman\n' $'Marriages\n' $'Chelsea Wolfe')
songs=($'Mer\n' $'Embassy Row\n' $'Torment of the Metals\n' $'The Liar\n' $'The Waves have Come')

我们可以使用 bash 后缀移除来移除那些换行符:

for ((i=0;i<"${#artists[@]}";++i));
do
    printf "%s - %s\n" "${artists[$i]%$'\n'}" "${songs[$i]%$'\n'}"
done

输出还是:

Chelsea Wolfe - Mer
Pavement - Embassy Row
Black Math Horseman - Torment of the Metals
Marriages - The Liar
Chelsea Wolfe - The Waves have Come

【讨论】:

  • 这适用于给出的示例数组,谢谢。它仍然会为我正在使用的实际数组生成artist artist artist - song song song 输出,但我会自己弄清楚(显然存储在这些数组中的元素不是我认为的格式)。我想我应该学习一种更有利于这种事情的语言(尽管尝试使用 Bash 是一种学习体验)。
  • 在不了解您的大型项目的情况下,很难知道该建议哪种语言。根据具体情况,Bash、awk 和 python 都可以。至于您的神秘数组,要找出 bash 数组中的实际内容,请运行 declare -p songs(将 songs 替换为您的数组名称)。这将为您提供有关数组内容的完整详细信息。
  • 看起来每个数组中都有换行符,每个元素都打印在单独的行上。简而言之:我想在本地记录我的音乐收听习惯,并且由于我已经使用 last.fm,我想我会使用他们的 API。理想情况下,我想将我的收听历史导出到 .csv 以绘制数据并发现趋势。我对 Python 知之甚少,但我认为它是最合适的。我可能可以在我熟悉的 R 中做我想做的事,当我想处理嵌入在 API 响应中的文本时,这并不是我想到的第一件事。不过,我敢打赌,它有一个包装!
  • 我用一种处理尾随换行符的方法更新了答案。另外,如果您想要 CSV 格式,那么您是对的:python 非常适合。使用 python 的csv package (import csv)。 Bash 和 awk 处理 CSV 格式的潜在复杂性的能力有限。
【解决方案2】:

我们可以通过paste 和一些进程替换来做到这一点:

$ paste <(printf "%s\n" "${artists[@]}") <(printf "%s\n" "${songs[@]}")
Chelsea Wolfe   Mer
Pavement    Embassy Row
Black Math Horseman Torment of the Metals
Marriages   The Liar
Chelsea Wolfe   The Waves have Come

有点乱,用column美化一下吧:

$ paste <(printf "%s\n" "${artists[@]}") <(printf "%s\n" "${songs[@]}") | column -t -s $'\t' -o " - "
Chelsea Wolfe       - Mer
Pavement            - Embassy Row
Black Math Horseman - Torment of the Metals
Marriages           - The Liar
Chelsea Wolfe       - The Waves have Come

【讨论】:

  • 第一个示例运行良好,格式很好,即使我使用的实际数组包含换行符。使用第二个示例,Bash 说 -o 选项无效。我也没有在手册页中看到它。我必须有一个旧版本。
【解决方案3】:

您苦苦挣扎的原因是,shell 是一个调用工具的环境,而不是用于操作文本的工具,因此编写 shell 脚本来操作文本非常困难。发明 shell 来调用 UNIX 工具的人也发明了 UNIX 工具 awk 让 shell 调用来操作文本,所以就用它吧:

$ cat tst.awk
BEGIN {
    FS=","; OFS=" - "

    split("Chelsea Wolfe,Pavement,Black Math Horseman,Marriages,Chelsea Wolfe",artists)
    split("Mer,Embassy Row,Torment of the Metals,The Liar,The Waves have Come",songs)

    for (i=1;i in artists;i++) {
        print artists[i], songs[i]
    }
}

$ awk -f tst.awk
Chelsea Wolfe - Mer
Pavement - Embassy Row
Black Math Horseman - Torment of the Metals
Marriages - The Liar
Chelsea Wolfe - The Waves have Come

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 2012-09-04
    • 2011-07-20
    • 2012-10-04
    • 2019-10-13
    • 2023-01-30
    相关资源
    最近更新 更多