像“column -t”这样的命令在输出中保留分隔符

像“column -t”这样的命令在输出中保留分隔符

我正在编辑一个简单的表格。我希望它的格式很好。虽然我可以使用tbllatex或类似的内容,但这似乎有点矫枉过正——纯文本确实足够了。因为很简单,我不妨将源作为输出。所以来源应该看起来也不错。这看起来应该是一个完美的工作column -s '|' -t——它找到分隔符并自动插入空格以根据每列中的最大宽度进行对齐。不幸的是,它删除了分隔符,因此我无法在进一步编辑后重新运行它。是否有任何好的文本处理工具可以幂等地完成此操作,以便其输出作为输入?还是我需要自己写?

编辑:这是我想要的示例:

foo |   bar | baz
abc def | 12 | 23456

应该成为

foo     | bar | baz
abc def | 12  | 3456

' '分隔符和垫片同时使用时,column -t效果很好。但我的物品中有空格,所以我不能使用它。使间隔物与分隔物不同使事情变得复杂。我认为在分隔符旁边将它们视为分隔符是有用的,但事实并非如此column -s '|' -t(尽管显然当前的行为也很有用)。

答案1

不确定我是否理解正确你的问题是什么。但是,添加一个额外的时间分隔符可以解决这个问题吗?因此,您可以使用第二个分隔符来标记分隔符,保持原始分隔符不变。

请参阅此示例,其中我向每个“|”添加了“@”所以列命令的输入将是“xxx @| yyyy”。列将处理“@”并保留“|”未受影响:

~$ echo "foo | this is some text | bar" | sed 's/|/@|/g'  | column -s '@' -t
foo   | this is some text   | bar

答案2

当您提出问题时,此功能不可用,但是自第 2.23 节起 columnfromutil-linux允许您通过选择输出分隔符

   -o, --output-separator string
          Specify the columns delimiter for table output (default is two spaces).

所以只需运行:

 column -s '|' -o '|' -t infile

答案3

这是一个 bash 脚本。它不使用“column -t”,并且分隔符的处理方式与 IFS 完全相同,因为它是 IFS(或者至少是 awk 的 IFS 内部版本)...默认分隔符是 $' \t'

该脚本完全填充了最右侧的字段。
“列”不执行此操作。
通过填充所有列,可以
轻松修改此脚本以创建表格框架。

笔记。输入文件需要处理两次
(“列”也需要执行此操作)
第一遍是获取列最大宽度。
第二遍是扩展字段(每列)

添加了一些选项并修复了一个明显的错误(重命名变量:(

  • -l 任何缩进字段的左侧修剪空白
  • -r 右侧修剪空白比最宽的文本更宽(对于列)
  • -b -l 和 -r
  • -L 添加左输出分隔符
  • -R 添加右输出分隔符
  • -B -L 和 -R
  • -S 选择输出分隔符

#!/bin/bash
#
#   script [-F sep] [file]
#
#   If file is not specified, stdin is read 
#    
# ARGS ######################################################################
l=;r=;L=;R=;O=;F=' ' # defaults
for ((i=1;i<=${#@};i++)) ;do
  case "$1" in
    -- ) shift 1;((i--));break ;;
    -l ) l="-l";shift 1;((i-=1)) ;;        #  left strip whitespace
    -r ) r="-r";shift 1;((i-=1)) ;;        # right strip whitespace
    -b ) l="-l";r="-r";shift 1;((i-=1)) ;; # strip  both -l and -r whitespace
    -L ) L="-L";shift 1;((i-=1)) ;;        #  Left output delimiter is added
    -R ) R="-R";shift 1;((i-=1)) ;;        # Right output delimiter is added
    -B ) L="-L";R="-R";shift 1;((i-=1)) ;; # output Both -L and -R delimiters
    -F ) F="$2";shift 2;((i-=2)) ;; # source separator
    -O ) O="$2";shift 2;((i-=2)) ;; # output  separator. Default = 1st char of -F 
    -* ) echo "ERROR: invalid option: $1" 1>&2; exit 1 ;;
     * ) break ;;
  esac
done
#
if  [[ -z "$1" ]] ;then # no filename, so read stdin
  f="$(mktemp)"
  ifs="$IFS"; IFS=$'\n'; set -f # Disable pathname expansion (globbing)
  while read -r line; do
    printf "%s\n" "$line" >>"$f"
  done
  IFS="$ifs"; set +f # re-enable pathname expansion (globbing)
else
  f="$1"
fi
[[ -f "$f" ]] || { echo "ERROR: Input file NOT found:" ;echo "$f" ;exit 2 ; }
[[ -z "$F" ]] && F=' '        # input Field Separator string
[[ -z "$O" ]] && O="$F"       # output Field Separator
                 O="${O:0:1}" #   use  single char only

# MAIN ######################################################################
max="$( # get max length of each field/column, and output them
  awk -vl="$l" -vr="$r" -vL="$L" -vR="$R" -vF="$F" -vO="$O" '
    BEGIN { if (F!="") FS=F }
    { for (i=1;i<=NF;i++) { 
        if (l=="-l") { sub("^[ \t]*","",$i) }
        if (r=="-r") { sub("[ \t]*$","",$i) }
        len=length($i); if (len>max[i]) { max[i]=len } 
        if (i>imax) { imax=i } 
      } 
    }
    END { for(i=1;i<=imax;i++) { printf("%s ",max[i]) } }
  ' "$f" 
)"

awk -vl="$l" -vr="$r" -vL="$L" -vR="$R" -vF="$F" -vO="$O" -v_max="$max" '
  BEGIN { if (F!="") FS=F; cols=split(_max,max," ") }
  { # Bring each field up to max len and output with delimiter
    printf("%s",L=="-L"?O:"")
    for(i=1;i<=cols;i++) { if (l=="-l") { sub("^[ \t]*","",$i) } 
                           if (r=="-r") { sub("[ \t]*$","",$i) }
      printf("%s%"(max[i]-length($i))"s%s",$i,"",i==cols?"":O) 
    } 
    printf("%s\n",R=="-R"?O:"")
  }
' "$f"

# END #######################################################################    
if  [[ -z "$1" ]] ;then # no filename, so stdin was used
  rm "$f"   # delete temp file
fi
exit

答案4

这是一个两遍调整赫蒙托柳的回答,这避免了需要通过从输入数据猜测分隔符来对分隔符进行硬编码。

  1. 解析由空格包围的单个非字母数字字符的输入,按最常见的字符对它们进行排序,并假设最常见的字符是分隔符,它被分配给$d
  2. 或多或少地进行赫莫诺柳的答案,但使用 ASCII无效的作为填充,而不是@按照彼得·奥的评论。

该代码是一个函数,它接受文件名,或者输入标准输入:

algn() { 
    d="$(grep -ow '[^[:alnum:]]' "${1:-/dev/stdin}"  | \
         sort | uniq -c | sort -rn | sed -n '1s/.*\(.$\)/\1/p')" ;
    sed "s/ *$d */\x01$d /g" "${1:-/dev/stdin}"  | column -s $'\001' -t ;
}

输出algn foo(或也algn < foo):

foo      | bar  | baz
abc def  | 12   | 23456

相关内容