在BASH中以两列输出文件

3
我想把一个文件在第n个行之后重新排列成两列。
例如,假设我有一个像这样的文件:
This is a bunch of text that I'd like to print as two columns starting at line number 7 and separated by four spaces. Here are some more lines so I can demonstrate what I'm talking about.
我想将它打印出来,像这样:
This is a bunch and separated by four spaces. of text Here are some that I'd like to print more lines so I can as two demonstrate columns starting what I'm talking about. at line number 7
如何使用bash命令或函数实现呢?
3个回答

4
事实上,pr 几乎可以完全做到这一点:
pr --output-tabs=' 1' -2 -t tmp1 

This is a bunch                     and separated by four spaces.
of text                             Here are some
that I'd like to print              more lines so I can
as two                              demonstrate
columns starting                    what I'm talking about.
at line number 7  

-2代表两列;-t用于省略页面标题;如果没有--output-tabs=' 1',则会在添加了8个空格后插入一个制表符。您还可以设置页面宽度和长度(如果您的实际文件比100行长得多)。查看man pr以获取一些选项。
如果您坚持“比左侧最长的行多四个空格”,那么也许您需要使用更复杂的东西;
以下内容适用于您的测试输入,但已经到了“已经使用Perl”的程度。
#!/bin/sh
infile=${1:-tmp1}
longest=$(longest=0;
          head -n $(( $( wc -l $infile | cut -d ' ' -f 1 ) / 2 )) $infile | \
              while read line
              do
                  current="$( echo $line | wc -c | cut -d ' ' -f 1 )"
                  if [ $current -gt $longest ]
                  then
                      echo $current
                      longest=$current
                  fi
              done | tail -n 1 )
pr -t -2 -w$(( $longest * 2 + 6 )) --output-tabs=' 1' $infile

This is a bunch           and separated by four spa
of text                   Here are some
that I'd like to print    more lines so I can
as two                    demonstrate
columns starting          what I'm talking about.
at line number 7          

重新阅读你的问题后,我想知道你是否意味着要字面上地向程序指定第 n 行,如果是这样,那么上述两种方法都不适用,除非该行恰好在中间位置。


同事建议我把愚蠢的 while 子进程改写成“map; sort; tail”模型管道,这样可能会更简单。tail 是因为 longest 的修改版本在管道创建的子进程中。如果有人对此有强烈的看法,我可以尝试重写它以通过 sort -n 而不是操纵临时变量,但我怀疑差异实际上微不足道。 - BRPocock

1
感谢chatraed和BRPocock(以及你们的同事)。你们的答案帮助我想出了这个解决方案,满足了我的需求。
function make_cols
{
     file=$1         # input file
     line=$2         # line to break at
     pad=$(($3-1))   # spaces between cols - 1

     len=$( wc -l < $file )
     max=$(( $( wc -L < <(head -$(( line - 1 )) $file ) ) + $pad ))

     SAVEIFS=$IFS;IFS=$(echo -en "\n\b")

     paste -d" " <( for l in $( cat <(head -$(( line - 1 )) $file ) )
           do
                printf "%-""$max""s\n" $l
           done ) \
           <(tail -$(( len - line + 1 )) $file )

     IFS=$SAVEIFS
}

make_cols tmp1 7 4

0

这段代码可以通过多种方式进行优化,但它能够按照要求完成工作。

输入数据(可配置):

  1. 文件
  2. 从文件中借用的行数,用于第一列
  3. 列之间的空格数

format.sh:

#!/bin/bash

file=$1
if [[ ! -f $file ]]; then
    echo "File not found!"
    exit 1
fi

spaces_col1_col2=4
rows_col1=6
rows_col2=$(($(cat $file | wc -l) - $rows_col1))

IFS=$'\n'
ar1=($(head -$rows_col1 $file))
ar2=($(tail -$rows_col2 $file))

maxlen_col1=0
for i in "${ar1[@]}"; do
    if [[ $maxlen_col1 -lt ${#i} ]]; then
        maxlen_col1=${#i}
    fi
done
maxlen_col1=$(($maxlen_col1+$spaces_col1_col2))

if [[ $rows_col1 -lt $rows_col2 ]]; then
    rows=$rows_col2
else
    rows=$rows_col1
fi

ar=()
for i in $(seq 0 $(($rows-1))); do
    line=$(printf "%-${maxlen_col1}s\n" ${ar1[$i]})
    line="$line${ar2[$i]}"
    ar+=("$line")
done

printf '%s\n' "${ar[@]}"

输出:

$ > bash format.sh myfile
This is a bunch           and separated by four spaces.
of text                   Here are some
that I'd like to print    more lines so I can
as two                    demonstrate
columns starting          what I'm talking about.
at line number 7
$ >

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接