按列组合文本文件

按列组合文本文件

我有两个文本文件。第一个内容为:

Languages
Recursively enumerable
Regular

而第二个的内容是:

Minimal automaton
Turing machine
Finite

我想将它们按列合并到一个文件中。所以我尝试了一下paste 1 2,它的输出是:

Languages   Minimal automaton
Recursively enumerable  Turing machine
Regular Finite

不过,我希望各列能够很好地对齐,例如

Languages               Minimal automaton
Recursively enumerable  Turing machine
Regular                 Finite

我想知道是否可以在不手动处理的情况下实现这一目标?


添加:

这是另一个例子,布鲁斯方法几乎成功了,除了一些轻微的错位,我想知道为什么?

$ cat 1
Chomsky hierarchy
Type-0

$ cat 2
Grammars
Unrestricted

$ paste 1 2 | pr -t -e20
Chomsky hierarchy   Grammars
Type-0              Unrestricted
—                    (no common name)

答案1

你只需要column命令,并告诉它使用制表符分隔列

paste file1 file2 | column -s $'\t' -t

为了解决“空单元格”争议,我们只需要以下-n选项column

$ paste <(echo foo; echo; echo barbarbar) <(seq 3) | column -s $'\t' -t
foo        1
2
barbarbar  3

$ paste <(echo foo; echo; echo barbarbar) <(seq 3) | column -s $'\t' -tn
foo        1
           2
barbarbar  3

我的专栏手册页显示-n是“Debian GNU/Linux 扩展”。我的 Fedora 系统没有出现空单元问题:它似乎源自 BSD,手册页显示“版本 2.23 将 -s 选项更改为非贪婪”

答案2

您正在寻找方便的命令pr

paste file1 file2 | pr -t -e24

“-e24”是“将制表位扩展至 24 个空格”。幸运的是,paste在列之间放置一个制表符,这样pr就可以展开它。我通过计算“递归可枚举”中的字符并添加 2 来选择 24。

答案3

更新:这里有一个更简单的脚本(问题末尾的脚本)用于表格输出。只需将文件名传递给它即可paste...它用于html制作框架,因此它是可调整的。它确实保留了多个空格,并且在遇到 unicode 字符时保留了列对齐方式。然而,编辑器或查看器渲染 unicode 的方式完全是另一回事......

┌──────────────────────┬────────────────┬──────────┬────────────────────────────┐
│ Languages            │ Minimal        │ Chomsky  │ Unrestricted               │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ Recursive            │ Turing machine │ Finite   │     space indented         │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ Regular              │ Grammars       │          │ ➀ unicode may render oddly │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│ 1 2  3   4    spaces │                │ Symbol-& │ but the column count is ok │
├──────────────────────┼────────────────┼──────────┼────────────────────────────┤
│                      │                │          │ Context                    │
└──────────────────────┴────────────────┴──────────┴────────────────────────────┘

#!/bin/bash
{ echo -e "<html>\n<table border=1 cellpadding=0 cellspacing=0>"
  paste "$@" |sed -re 's#(.*)#\x09\1\x09#' -e 's#\x09# </pre></td>\n<td><pre> #g' -e 's#^ </pre></td>#<tr>#' -e 's#\n<td><pre> $#\n</tr>#'
  echo -e "</table>\n</html>"
} |w3m -dump -T 'text/html'

---

工具概要答案中提出(到目前为止)。
我非常仔细地观察过它们;这是我发现的:

paste# 这个工具对于迄今为止提出的所有答案都是通用的 # 它可以处理多个文件;因此多列...好! # 它用制表符分隔每一列...很好。 # 其输出未制成表格。

下面的所有工具都删除了这个分隔符!...如果您需要分隔符,那就不好了。

column# 它删除了制表符分隔符,因此字段标识纯粹是按列进行的,它似乎处理得很好..我没有发现任何错误... # 除了没有唯一的分隔符之外,它工作得很好!

expand# 只有单个制表符设置,因此超出2列是不可预测的 # 处理unicode时列的对齐不准确,并且它删除了制表符分隔符,因此字段识别纯粹通过列对齐

pr# 只有一个选项卡设置,因此超过 2 列是不可预测的。 # 处理unicode时列的对齐不准确,并且它删除了制表符分隔符,因此字段识别纯粹通过列对齐

对我来说,column这显然是最好的单行解决方案。如果您想要分隔符或文件的 ASCII 艺术制表符,请继续阅读,否则...columns非常好:)...


这是一个脚本,它接受任意数量的文件并创建一个 ASCII-art 表格演示文稿。(请记住,unicode 可能无法呈现预期的宽度,例如 ௵,它是单个字符。这与列有很大不同数字是错误的,就像上面提到的一些实用程序中的情况一样。)...脚本的输出(如下所示)来自 4 个输入文件,名为 F1 F2 F3 F4...

+------------------------+-------------------+-------------------+--------------+
| Languages              | Minimal automaton | Chomsky hierarchy | Grammars     |
| Recursively enumerable | Turing machine    | Type-0            | Unrestricted |
| Regular                | Finite            | —                 |              |
| Alphabet               |                   | Symbol            |              |
|                        |                   |                   | Context      |
+------------------------+-------------------+-------------------+--------------+

#!/bin/bash

# Note: The next line is for testing purposes only!
set F1 F2 F3 F4 # Simulate commandline filename args $1 $2 etc...

p=' '                                # The pad character
# Get line and column stats
cc=${#@}; lmax=                      # Count of columns (== input files)
for c in $(seq 1 $cc) ;do            # Filenames from the commandline 
  F[$c]="${!c}"        
  wc=($(wc -l -L <${F[$c]}))         # File length and width of longest line 
  l[$c]=${wc[0]}                     # File length  (per file)
  L[$c]=${wc[1]}                     # Longest line (per file) 
  ((lmax<${l[$c]})) && lmax=${l[$c]} # Length of longest file
done
# Determine line-count deficits  of shorter files
for c in $(seq 1 $cc) ;do  
  ((${l[$c]}<lmax)) && D[$c]=$((lmax-${l[$c]})) || D[$c]=0 
done
# Build '\n' strings to cater for short-file deficits
for c in $(seq 1 $cc) ;do
  for n in $(seq 1 ${D[$c]}) ;do
    N[$c]=${N[$c]}$'\n'
  done
done
# Build the command to suit the number of input files
source=$(mktemp)
>"$source" echo 'paste \'
for c in $(seq 1 $cc) ;do
    ((${L[$c]}==0)) && e="x" || e=":a -e \"s/^.{0,$((${L[$c]}-1))}$/&$p/;ta\""
    >>"$source" echo '<(sed -re '"$e"' <(cat "${F['$c']}"; echo -n "${N['$c']}")) \'
done
# include the ASCII-art Table framework
>>"$source" echo ' | sed  -e "s/.*/| & |/" -e "s/\t/ | /g" \'   # Add vertical frame lines
>>"$source" echo ' | sed -re "1 {h;s/[^|]/-/g;s/\|/+/g;p;g}" \' # Add top and botom frame lines 
>>"$source" echo '        -e "$ {p;s/[^|]/-/g;s/\|/+/g}"'
>>"$source" echo  
# Run the code
source "$source"
rm     "$source"
exit

这是我原来的答案(稍微修改一下以代替上面的脚本)

用于wc获取列宽,并sed用 a 向右填充可见的字符.(仅用于此示例)...然后paste用 a 连接两列标签字符...

paste <(sed -re :a -e 's/^.{1,'"$(($(wc -L <F1)-1))"'}$/&./;ta' F1) F2

# output (No trailing whitespace)
Languages.............  Minimal automaton
Recursively enumerable  Turing machine
Regular...............  Finite

如果你想填充右列:

paste <( sed -re :a -e 's/^.{1,'"$(($(wc -L <F1)-1))"'}$/&./;ta' F1 ) \
      <( sed -re :a -e 's/^.{1,'"$(($(wc -L <F2)-1))"'}$/&./;ta' F2 )  

# output (With trailing whitespace)
Languages.............  Minimal automaton
Recursively enumerable  Turing machine...
Regular...............  Finite...........

答案4

我无法对 Glenn jackman 的答案发表评论,因此添加此内容是为了解决 Peter.O 指出的空单元格问题。在每个选项卡之前添加空字符可以消除被视为单个分隔符的分隔符运行并解决该问题。 (我最初使用空格,但使用空字符消除了列之间的额外空格。)

paste file1 file2 | sed 's/\t/\0\t/g' | column -s $'\t' -t

如果空字符由于各种原因导致问题,请尝试:

paste file1 file2 | sed 's/\t/ \t/g' | column -s $'\t' -t

或者

paste file1 file2 | sed $'s/\t/ \t/g' | column -s $'\t' -t

两者的实现sed似乎column在 Unix/Linux 风格和版本之间有所不同,尤其是 BSD(和 Mac OS X)与 GNU/Linux。

相关内容