【问题标题】:Bash - Print CSV FileBash - 打印 CSV 文件
【发布时间】:2012-07-04 10:54:24
【问题描述】:

我正在尝试使用某些列宽打印 CSV 文件。我认为 i 有一个错误导致第一列不打印。正如您将看到的,我是 bash 的新手,并且拼命想让它表现得像 C。

CSV='./test.csv'
column_width=(20 6 5 10 10 10 10 8 30)

IFS=","
        while read LINE
        do
                set -- $LINE
                arg=($@)
                for (( i = 0 ; i < ${#arg[@]} ; i++))
                do
                        case $i in
                                1) printf "%-20s"   ${arg[$i]} ;;
                                2) printf "%-6s"    ${arg[$i]} ;;
                                3) printf "%-5s"    ${arg[$i]} ;;
                                4) printf "%-10s"   ${arg[$i]} ;;
                                5) printf "%-10s"   ${arg[$i]} ;;
                                6) printf "%-10s"   ${arg[$i]} ;;
                                7) printf "%-10s"   ${arg[$i]} ;;
                                8) printf "%-8s"    ${arg[$i]} ;;
                                9) printf "%-30s\n" ${arg[$i]} ;;
                        esac
                done
        done < $CSV
        unset IFS

我也无法将 case 语句转换为循环。无济于事,我尝试将整个 C 风格的 for 循环替换为:

for i in "${arg[@]}"; do
        printf "%-${column_width[$i]}s" ${arg[$i]}
done

我确信有更好的方法来实现这一点。我正在尝试了解 sed/awk,但我现在想知道在没有它们的情况下如何做到这一点。

【问题讨论】:

  • 您的 case 语句未涵盖 $i==0,因此跳过了第一列。
  • 谢谢。我本可以更仔细地阅读。

标签: bash csv


【解决方案1】:

我认为脚本非常优雅。你将很难用任何语言更简洁地做到这一点(尽管这使用了我不喜欢的 bashisms :->)

由于我更倾向于避免脚本逻辑和使用您的编辑器的宏功能方面,所以这是我的版本。

#!/bin/sh

CSV='./test.csv'

while IFS=, read one two three four five six seven eight nine
do
    test "$one"   && printf %s-20s "$one"
    test "$two"   && printf %s-6s  "$two"
    test "$three" && printf %s-5s  "$three"
    test "$four"  && printf %s-10s "$four"
    test "$five"  && printf %s-10s "$five"
    test "$six"   && printf %s-10s "$six"
    test "$seven" && printf %s-10s "$seven"
    test "$eight" && printf %s-8s  "$eight"
    test "$nine"  && printf %s-30s "$nine"
    printf \\n
done < "$CSV"   # mind the quoting

我个人认为它更令人赏心悦目(并且没有 bashisms!),但是 YMMV。我也会避免进行大量测试,但如果可能,只需打印即可。

【讨论】:

  • 这比 ormaaj 的简洁版本更具可读性,但是,“bashisms”正是我想要学习的。 :)
  • 我知道我不会告诉你什么时候我认为你问的是错误的答案或错误的问题,但我认为你真的应该想出一个不容易解决的问题简单的sh 风格。当您创建了这样的示例时,您可能会注意到它在 bash 中也会非常麻烦;-)。抱歉拖钓。
【解决方案2】:

干得好,对立。

脚本中的错误是因为即使在 Bash 中数组索引也以 0 开头,而您的 switch case 不是。我能想到的最小变化是“移动”数组arg。尝试使用arg=(0 $@)。您可以在数组的第 0 个索引处使用任何其他值。将处理不存在的 0 情况。

【讨论】:

    【解决方案3】:
    #!/usr/bin/env bash
    
    csv=./test.csv
    column_width=(20 6 5 10 10 10 10 8 30)
    
    while n=0; IFS=, read -ra x; do
        printf '%-*s' {,,,,,,,,}{"${column_width[n]}","${x[n++]}"} 1 $'\n'
    done <"$csv"
    

    【讨论】:

    • +1 尽管有类似 Perl 的不可理解性。 :) 不过,每次迭代都需要将 n 重置为 0。
    • @chepner 谢谢修复。可能很好,我没有展示每行处理不同数量字段的版本。 :)
    • 这正是我想要的;简洁的东西。它看起来很好地使用了内置的 bash 命令(虽然我可能不会意识到不好用)。请随时发布具有不同字段的版本。
    猜你喜欢
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    • 1970-01-01
    • 2015-01-19
    • 2019-07-15
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多