Answers:
某些系统具有truncate
将文件截断为多个字节(不是字符)的命令。
我不知道会截断许多字符,尽管您可以perl
使用大多数系统默认安装的字符:
perl -Mopen=locale -ne '
BEGIN{$/ = \1234} truncate STDIN, tell STDIN; last' <> "$file"
使用-Mopen=locale
,我们使用语言环境中的字符概念(因此,在使用UTF-8字符集的语言环境中,即UTF-8编码的字符)。-CS
如果您希望以UTF-8格式对I / O进行解码/编码,而不考虑语言环境的字符集,请替换为。
$/ = \1234
:我们将记录分隔符设置为对整数的引用,这是一种指定固定长度(以字符数表示)的记录的方法。
然后在读取第一条记录后,我们将stdin截断到位(因此在第一条记录的末尾)并退出。
使用GNU sed
,您可以做到(假设文件不包含NUL字符或不构成有效字符的字节序列-文本文件都应为真):
sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
但这效率要低得多,因为它会完整读取文件并将其完整存储在内存中,然后写入新副本。
与GNU相同awk
:
awk -i inplace -v RS='^$' -e '{printf "%s", substr($0, 1, 1234)}' -E /dev/null "$file"
-e code -E /dev/null "$file"
是将任意文件名传递给的一种方法 gawk
RS='^$'
:lur饮模式。使用ksh93
,bash
或zsh
(zsh
假设内容不包含NUL字节,则使用非shell ):
content=$(cat < "$file" && echo .) &&
content=${content%.} &&
printf %s "${content:0:1234}" > "$file"
与zsh
:
read -k1234 -u0 s < $file &&
printf %s $s > $file
要么:
zmodload zsh/mapfile
mapfile[$file]=${mapfile[$file][1,1234]}
使用ksh93
或bash
(请注意,在多个版本中,多字节字符是虚假的bash
):
IFS= read -rN1234 s < "$file" &&
printf %s "$s" > "$file"
ksh93
也可以在适当的位置截断文件,而不用其<>;
重定向操作符重写它:
IFS= read -rN1234 0<>; "$file"
要打印前1234个字符,另一种选择是将其转换为每个字符具有固定字节数的编码,例如UTF32BE
/ UCS-4
:
iconv -t UCS-4 < "$file" | head -c "$((1234 * 4))" | iconv -f UCS-4
head -c
不是标准的,而是相当普遍的。一个等效的标准将是dd bs=1 count="$((1234 * 4))"
有效的,但是效率较低,因为它将一次读取输入并将输出写入一个字节¹。iconv
是标准命令,但编码名称未标准化,因此您可能会发现系统中没有UCS-4
在任何情况下,尽管输出最多包含1234个字符,但它最终可能不是有效的文本,因为它可能会以无界线结尾。
同时还要注意,而这些解决方案将不能在字符的中间切开文字,他们就能把它在中间字形,像一个é
表示为U + 0065 U + 0301(一个e
接着一个组合重音符)或以分解形式显示的韩文音节字素。
¹并且在管道输入上,bs
除非使用iflag=fullblock
GNU扩展名,否则您不能可靠地使用非1的值,dd
如果它读取管道的速度比iconv
填充管道快,则可能会进行短读
dd bs=1234 count=4
如果您知道文本文件包含以UTF-8编码的Unicode,则必须首先对UTF-8进行解码以获取一系列Unicode字符实体并将其拆分。
我会选择Python 3.x做这项工作。
在Python 3.x中,函数open()具有一个额外的关键字参数,encoding=
用于读取文本文件。方法io.TextIOBase.read()的描述看起来很有希望。
因此,使用Python 3看起来像这样:
truncated = open('/path/to/file.txt', 'rt', encoding='utf-8').read(1000)
显然,真正的工具会添加命令行参数,错误处理等。
使用Python 2.x,您可以实现自己的类似文件的对象,并逐行解码输入文件。
我想添加另一种方法。可能不是最佳性能明智的选择,而且可能更长一些,但很容易理解:
#!/bin/bash
chars="$1"
ifile="$2"
result=$(cat "$ifile")
rcount=$(echo -n "$result" | wc -m)
while [ $rcount -ne $chars ]; do
result=${result::-1}
rcount=$(echo -n "$result" | wc -m)
done
echo "$result"
用调用它$ ./scriptname <desired chars> <input file>
。
这会逐个删除最后一个字符,直到达到目标为止,这似乎是非常糟糕的性能,特别是对于较大的文件。我只是想提出这个想法,以显示更多的可能性。
wc
进入文件一半的目标点,计数的总数为O(n ^ 2)个字节。通过使用增加或减少的变量(例如echo -n "${result::-$chop}" | wc -m
或类似的东西),应该可以进行二进制搜索而不是线性搜索 。(并且在使用时,即使文件内容以开头-e
或类似的内容(可能使用printf
)也要确保其安全。)但是您仍然不会击败只看一次每个输入字符的方法,因此可能不值得。
$result
直到匹配所需的长度为止,但是如果所需的长度较大,则效率同样低下。
$desired_chars
低端或高端开始以接近字节的位置开始4*$desired_chars
。但是我仍然认为最好完全使用其他东西。
cut
仍然不支持多字节字符。如果这样做,您可以做cut -zc-1234 | tr -d '\0'
。