什么命令将提供制表符分隔的文本文件并将每行剪切为 80 个字符?

什么命令将提供制表符分隔的文本文件并将每行剪切为 80 个字符?

我有(有时)制表符分隔数据的多行文本文件。我想输出该文件,以便我可以浏览它 - 所以我只想看到每行的前 80 个字符(我设计的文本文件将重要的内容放在每行的前面)。

我以为我可以使用 cat 读取文件的每一行,并将每一行发送到管道中的下一个命令:

cat tabfile | cut -c -80

但这似乎被打破了。我试着胡闹,grep 似乎可以工作 - 但后来我发现,不,它没有(不是文件中的每一行都有 80 多个字符) - 似乎制表符被剪切计为单个字符。

我试过:

cat tabfile | tr \t \040 | cut -c -80

尽管这会通过消除空白可读性来稍微破坏我的数据。但这没有用。也没有:

cat tabfile | tr \011 \040 | cut -c -80

也许我用错了tr?我以前在 tr 上遇到过麻烦,想要删除多个空格(似乎我在这台机器上可以访问的 tr 版本有一个 -s 选项用于压缩多个字符 - 我可能需要更多地使用它)

我确信如果我乱搞的话我可以使用 perl、awk 或 sed 或其他东西来做到这一点。

但是,我想要一个使用(POSIX?)常规命令的解决方案,以便它尽可能可移植。如果我最终使用 tr,我可能最终会尝试将制表符转换为字符,也许进行计算,剪切计算,然后将这些字符转换回制表符以进行输出。

它不需要是单行/直接在命令行上输入 - 脚本就可以。


有关选项卡文件的更多信息:

我使用制表符来分隔字段,因为有一天我可能想将数据导入到其他程序中。因此,我倾向于在内容之间只有一个选项卡。但我还使用制表符将内容与垂直列对齐,以提高查看纯文本文件时的可读性。这意味着对于某些文本片段,我会用空格填充内容的末尾,直到到达选项卡将下一个字段与其上方和下方的字段对齐的位置。

DarkTurquoise #00CED1 海洋、天空、划艇自然
MediumSpringGreen #00FA9A 对树木有用魔法  
青柠 #00FF00 仅适用于春鸡和水果$

答案1

我认为您正在寻找expand和/或unexpand。看来您正在尝试确保\tab 宽度算作 8 个字符而不是单个字符。fold也会这样做,但它将把输入包装到下一行而不是截断它。我想你想要:

expand < input | cut -c -80

expand并且unexpand都是POSIX 指定:

  • expand实用程序应将文件或标准输入写入标准输出,并将\tab 字符替换为一个或多个空间填充到下一个制表位所需的字符。任何退格键字符应复制到输出并导致制表位计算的列位置计数递减;列位置计数不得减少到零以下。

很简单。那么,我们来看看它的作用:

unset c i; set --;                                                             
until [ "$((i+=1))" -gt 10 ]; do set -- "$@" "$i" "$i"; done                      
for c in 'tr \\t \ ' expand;  do eval '                                           
    { printf "%*s\t" "$@"; echo; } | 
      tee /dev/fd/2 |'"$c"'| { 
      tee /dev/fd/3 | wc -c >&2; } 3>&1 |
      tee /dev/fd/2 | cut -c -80'
done

顶部的循环until获取一组数据,例如......

1 1 2 2 3 3 ...

printf带有%*sarg 填充标志,因此对于集合中的每个参数,printf将填充与参数数量一样多的空格。它为每个附加一个\tab 字符。

所有的tees 都用于显示应用每个过滤器时的效果。

效果如下:

1        2        3        4        5        6        7        8                9               10
1  2   3    4     5      6       7        8         9         10 
1  2   3    4     5      6       7        8         9         10 
66
1        2        3        4        5        6        7        8                9               10
1        2        3        4        5        6        7        8                9               10 
1        2        3        4        5        6        7        8                
105

这些行排列成两组,就像......

  1. 的输出printf ...; echo
  2. tr ...或的输出expand
  3. 的输出cut
  4. 的输出wc

前四行是tr过滤器的结果 - 其中每个\tab 都转换为单个空间

以及最后四名连锁的结果expand

答案2

由于选项卡更多的是用于对齐而不是分隔,一种方法可能是使用columnand then cut

column -s '\t' -t <some-file | cut -c -80

看来column不是POSIX。它是 Ubuntu 上 BSD 实用程序的一部分,所以我认为它是相当跨平台的。

答案3

唐在评论中的建议是一个好的开始。

这就是我让它(大部分)工作所需的:

pr +1 -1 -t -m -l1000 -w 80 tabfile

需要-m使-w标志在单个列上生效。手册页可以使用一些重写来表明这一点。

在尝试解决方法时,我发现pr输出\t字符,因此输入其结果会cut导致相同的问题。

-1(列标志)在手册页中具体说明:

此选项不应与 -m 一起使用。

但是,如果没有此选项,pr则会以比指定长度短得多的方式任意截断行。

pr还在字段中的每个单词之前(或之后?)插入一个空格(即我有一个空格的每个地方,处理后有两个空格)。如果单词太多,插入的空格将忽略-w限制(创建环绕)。但是,奇怪的是,否则非制表符分隔(即空格排列)的“列”保持对齐。

答案4

一个应该真正了解显示宽度的实用程序是fold:不幸的是,它似乎没有选择丢弃而不是换行的选项。虽然它可能效率非常低,但是你可以做类似的事情

while read -r line; do fold -w80 <<< "$line" | head -n1; done < file

相关内容