【问题标题】:How to output an array's content in columns in BASH如何在 BASH 的列中输出数组的内容
【发布时间】:2010-06-10 13:41:09
【问题描述】:

我想从一个数组中显示一长串字符串。

现在,我的脚本运行一个 for 循环,将每个值回显到标准输出:

for value in ${values[@]}
do
  echo $value
done

是的,这很丑!而且一栏列表也很长...

我想知道是否可以找到一个命令或内置命令来帮助我在列中显示所有这些值,就像列出目录 (ls -C) 时默认情况下的 ls 命令一样。

[更新]

column 无法显示格式正确的列让我不知所措,这里有更多信息:

价值观:

$ values=( 01----7 02----7 03-----8 04----7 05-----8 06-----8 07-----8 08-----8 09---6 10----7 11----7 12----7 13----7 14-----8 15-----8 16----7 17----7 18---6 19-----8 20-----8 21-----8)

注意前两位数字作为索引,最后一位指示字符串长度以便于阅读。

命令:echo " ${values[@]/%/$'\n'}" | column

结果:bad columns http://tychostudios.ch/multipurpose/bad_columns.png

出了点问题……

【问题讨论】:

  • column 似乎在努力解决您的输入只有一列并且某些行比制表位更窄的事实。 echo " ${values[@]/%/$' \n'}" | column 似乎有效
  • @Johnsyweb:我必须在\n 之前添加另一个空格才能使其与该组数据一起使用。但奇怪的是,输出仅在 3 列上。虽然有足够的空间容纳 5 列。
  • @Arko:SO.com 在\n 之前吞下了我的双倍空格! echo " ${values[@]/%/$' \n'}" | column -c 120 为我提供了五列。
  • 再一次,换行前我的空间减半了!
  • @Johnsyweb:事实上,SO 并没有吞噬你的空间。它是一项 HTML 功能,默认情况下将多个空格呈现为一个。看看源头,它们就在那里。

标签: arrays bash list


【解决方案1】:

您可以将您的输出通过管道传输到column

column 似乎很难处理单列输入中的某些数据比制表位(8 个字符)窄。

for 循环中使用 printf 将值填充到 8 个字符似乎可以解决问题:

for value in "${values[@]}"; do 
    printf "%-8s\n" "${value}"
done | column

【讨论】:

  • +1 正确! column 用于列输出,column -x 用于行输出。
  • 和@Dennis:不错!这正是我一直在寻找的。但结果并不完美:根据字符串的长度,柱子上有时会出现孔洞。感觉就像它以某个宽度捕捉列大小(如在值之间插入标签),但不考虑最大值长度来计算列总宽度。 ls 命令确实会处理此问题以获得干净的输出。
  • printf "%-8s\n" "${value[@]}" | column 也可以。
【解决方案2】:

这里有一些技术可以与Johnsyweb's answer 一起使用,这样您就可以在没有循环的情况下进行输出:

saveIFS=$IFS
IFS=$'\n'
echo "${values[*]}" | column
IFS=$saveIFS

echo " ${arr[@]/%/$'\n'}" | column

echo " ${arr[@]/%/$'\n'}" | sed 's/^ //' | column

【讨论】:

  • 不错!三种技术都试过了,结果大致相同。请参阅我对@Johnysweb 答案的评论。
  • @Arko:如果没有看到您的数据,就不可能提出任何进一步的建议。 columns 确实使用制表符,它还根据最长字符串的长度调整列数。
  • 我的数据是一个简单的字符串数组,例如`values=(一二三四五)'。我肯定错过了什么。无法获得格式正确的列。将使用更多信息更新问题。
  • @Arko:使用您提供的命令,您的数据对我来说完美排列。我无法准确重现您的屏幕截图显示的内容,但我通过将终端窗口缩小到 60 个字符宽并在发出 echo ... column 命令之前发出 tabs -10 命令来接近。
  • 我期待您的回答。问题是特定于我的计算机。我会尝试找出原因。与此同时,我找到了另一种“方式”来做到这一点......看看我自己的答案。 ;)
【解决方案3】:

我知道这是一个旧线程,但我从列中得到不稳定的结果,所以我想我会给出我的解决方案。我想将每 3 行分组为 3 个均匀间隔的列。

cat file.txt | xargs printf '%-24s\n' | sed '$p;N;s/\n//;$p;N;s/\n//'

基本上,它将每一行输入到 printf 中,printf 将其左对齐到一个 24 字符宽的空白块中,然后将其输入到 sed 中。 sed 将向前看 2 行,并删除换行符。

N 命令将下一行读入当前缓冲区,s/\n// 删除换行符。简而言之,我们想要的是 'N;N;s/\n//g',它在某些情况下会起作用。问题是,如果缓冲区中没有两条额外的行,sed 将突然退出。 $p 命令通过说“如果这是最后一行,立即打印缓冲区内容”来抢占先机。

【讨论】:

  • 这是与问题不同的场景。您可能应该将其作为另一个问题发布。
  • 这是对我的问题的一个很好的回答。我需要在不使用列的情况下输出列。
【解决方案4】:

这可能看起来有点矫枉过正,但我​​想出了自己的解决方案。我写了一个小脚本,它完全符合我的要求:获取一个值列表并将它们输出到一个格式化的列视图中。

http://github.com/Arko/Columnize

【讨论】:

  • 建议:整数比较:if (( ${#value} > $longest_value )) 和其他人,你在其他地方使用(()) - 你也可以在这里:((columns = term_width / (longest_value + 2) ))((spaces_missing = longest_value - value_len + 2 )),而不是在 for 循环中回显空格:printf "%*s" $spaces_missing
  • @Dennis Williamson:已提交更改!我知道for 循环很尴尬...谢谢您的建议! :-)
【解决方案5】:

我知道这是一个旧线程,但我遇到了同样的情况。我最终结合了这里的一些想法。

对于基于列实用程序的解决方案(没有初始空间问题):

(IFS=''; echo "${values[*]/%/$'\n'}") | column

使用@Arko 的脚本作为基础,这可以处理带有空格的值。请注意 %-*s 的 printf 规范,用于左对齐的列,而右对齐的列会删除“-”。我没有包括我的终端猜测,但它是可设置的(终端宽度)。

#  e.g.  column "$@"
#        spacing=4 column "$@"
#        left=6 spacing=3 column "$@"
#
function column() {
    local leftMargin=${left:-0}
    local padding=${spacing:-2}
    local maxWidth=$(( ${terminalWidth:-80} - $leftMargin ))
    local values=("$@")
    local max=$(( $(IFS=''; echo "${values[*]/%/$'\n'}" | wc -L) + $padding ))
    local cols=$(( $maxWidth / $max ))

    local pos=0 NL=''
    for value in "${values[@]}"; do
        [[ $pos == 0 ]] && {
            printf "$NL%*s" "$leftMargin"
            NL=$'\n'  # add newlines from now on...
        }
        printf "%-*s" "$max" "$value"
        (( pos = ($pos + 1) % $cols ))
    done
    echo

}

【讨论】:

    【解决方案6】:

    由于某种原因,column 对我不起作用。就我而言,我有一个类似

    的数组
    $ array = ( 1 2 3 dir1 dir2 dir3 )
    $
    $ echo ${array[@]} | column            
    1 2 3 dir1 dir2 dir3
    

    我用了

    $ echo ${array[@]} | tr ' ' '\n' | sort
    1
    2
    3
    dir1
    dir2
    dir3
    

    【讨论】:

    • 试试:IFS=$'\n' echo "${array[@]}" | column
    【解决方案7】:

    制表符


    在每个值后使用制表符。

    (它也会自动流到下一行...)

    for value in ${values[@]}
    do
      echo -en "$value\t"
    done
    

    详细信息here

    祝你好运!!
    - CVS

    【讨论】:

    • 我很确定你的意思是echo -en "$value\t"
    猜你喜欢
    • 2014-03-28
    • 2018-03-05
    • 2012-10-19
    • 2012-08-11
    • 2011-09-19
    • 2014-08-05
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多