我有一个脚本,输入了 25,000 个字符,我在其中使用了“剪切”:
...\n" | cut -c -$LENGTH
我不经常使用它,但它正在工作(哦,大约一两年前)。当然,我的系统管理员可能已经运行了一些更新,但我认为基本实用程序的更改不会再发生了。看来我错了。
现在它抛出一个错误:
cut: [-bcf] list: 3080 too large (allowed 1-2048)
...在我的终端中,这甚至不是一整页的文本/字符。
是否有任何 POSIX 实用程序可以从更大的文本块中取出任意块?或者我必须使用 awk/sed/perl 吗?然后担心每次我不经常使用这个东西时会改变那些?
OpenBSD 6.4
没有可剪切的版本。男人说:
剪切实用程序符合 IEEE Std 1003.1-2008(“POSIX.1”)规范。
OpenBSD 6.4 2016 年 10 月 24 日 OpenBSD 6.4
答案1
符合 IEEE Std 1003.1-2008(“POSIX.1”)规范
本规范的cut
(以及较新的)说:
输入文件应为文本文件,但行长度不受限制
以下定义文本文件:
包含字符的文件,这些字符被组织成零行或多行。这些行不包含 NUL 字符,并且任何行的
{LINE_MAX}
长度都不能超过字节,包括 <newline> 字符。[…]
关于{LINE_MAX}
:
{LINE_MAX}
除非另有说明,当实用程序被描述为处理文本文件时,实用程序输入行(标准输入或其他文件)的最大长度(以字节为单位)。长度包括尾随 <newline> 的空间。
最小可接受值:{_POSIX2_LINE_MAX}
{_POSIX2_LINE_MAX}
除非另有说明,当实用程序被描述为处理文本文件时,实用程序输入行(标准输入或其他文件)的最大长度(以字节为单位)。长度包括尾随 <newline> 的空间。
价值:2048
看起来不应该拒绝使用任意长度的行,但这并不意味着orcut
不能有任何限制。您观察到的约束很可能是由于(假设)或(固定)(参见-c
-b
allowed 1-2048
{LINE_MAX}
{_POSIX2_LINE_MAX}
这条评论)。
一般来说{_POSIX2_LINE_MAX}
应该是一个安全值。{LINE_MAX}
可能更大,但至少是{_POSIX2_LINE_MAX}
2048。
比较其中之一例子:
POSIX.1-2008 本卷中的大多数实用程序都适用于文本文件。 cut 实用程序可用于将任意行长度的文件转换为一组包含相同数据的文本文件。粘贴实用程序可用于创建(或重新创建)具有任意行长度的文件。例如,如果文件包含长行:
cut -b 1-500 -n file > file1 cut -b 501- -n file > file2
创建
file1
行不超过 500 字节(加上 <newline>)的(文本文件),并且file2
包含文件中的其余数据。 (请注意,file2
如果文件中的行长于字节,则不是文本文件。)可以使用以下命令重新500 + {LINE_MAX}
创建原始文件:file1
file2
paste -d "\0" file1 file2 > file
这提供了一种“从更大的文本块中取出任意块”的 POSIX 方法:从每行的开头剪切 2048 或更少的字节,根据需要多次剪切以获得所需的总数。例如,如果每行需要 3080 个字节,则可以先取出 2000 个字节,然后再取出剩余的 1080 个字节:
cut -b 1-2000 file > file1 # first 2000 bytes
cut -b 2001- file > file2 # remainder
cut -b 1-1080 file2 > file3 # following 1080 bytes
paste -d "\0" file1 file3 > file_final # desired 3080 bytes (or less) per line
请注意,如果您cut
恰好是 2048 字节,则附加换行符的结果行可能会超过 2048 字节,并且(如果我正确解释文档)可能不会被视为文本文件。因此我最多会使用 2047,以防万一。
答案2
OpenBSD 上的实用cut
程序始终限制给定-c
选项的范围的最终值_POSIX2_LINE_MAX
(在 OpenBSD 上为 2048,请参阅 参考资料getconf _POSIX2_LINE_MAX
)。
2018年初,一个导致命令行选项解析出现分段错误的bug已修复。该实用程序的补丁会影响负责输出您看到的错误的代码区域,但我不确定这是否改变了该实用程序针对您的特定用例的行为。-c -3080
甚至在应用此补丁之前,实用程序就应该抱怨。
要使用 将文件剪切为任意行长度cut
,请参阅卡米尔的回答。
另一种可能性是切换到 Perl(在 OpenBSD 基本系统中可用):
perl -pe '$_=substr($_,0,3080)' file
或者,对于任意$LENGTH
长度:
perl -pe 'BEGIN { $len = $ARGV[0]; shift @ARGV } $_=substr($_,0,$len)' "$LENGTH" file
这模拟了cut -b
, 将cut -c
添加-Mopen=locale
到 Perl 的选项中。
如果没有给出文件名,该命令将从标准输入读取。
封装成shell函数:
pcut () {
perl -pe 'BEGIN { $len = $ARGV[0]; shift @ARGV } $_=substr($_,0,$len)' "$@"
}
这将用作
some-command | pcut "$LENGTH"
请注意,sed
and awk
(它们是 POSIX 实用程序)有一个限制,即它们的输入文件必须是文本文件。 “文本文件”在严格的 POSIX 意义上是指长度小于字节的换行符分隔字符串的文件_POSIX2_LINE_MAX
。 Perl 不是 POSIX 实用程序,因此不受此限制。