В некоторых системах есть truncate
команда, которая усекает файлы до количества байтов (не символов).
Я не знаю ни одного, который усекает число символов, хотя вы могли бы прибегнуть к тому, perl
который установлен по умолчанию на большинстве систем:
Perl
perl -Mopen=locale -ne '
BEGIN{$/ = \1234} truncate STDIN, tell STDIN; last' <> "$file"
С помощью -Mopen=locale
мы используем понятие локали о том, что такое символы (поэтому в локалях, использующих кодировку UTF-8, это символы в кодировке UTF-8). Замените на, -CS
если вы хотите, чтобы ввод / вывод декодировался / кодировался в UTF-8 независимо от кодировки локали.
$/ = \1234
: мы устанавливаем разделитель записей на ссылку на целое число, которое является способом указания записей фиксированной длины (в количестве символов ).
затем, прочитав первую запись, мы обрезаем stdin на месте (то есть в конце первой записи) и завершаем работу.
GNU sed
С GNU sed
вы могли бы это сделать (предполагая, что файл не содержит символов NUL или последовательностей байтов, которые не образуют допустимых символов - оба из которых должны быть истинными для текстовых файлов):
sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
Но это гораздо менее эффективно, поскольку он читает файл полностью, сохраняет его в памяти и записывает новую копию.
GNU awk
То же самое с 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='^$'
: режим slurp .
Встроенные оболочки
С ksh93
, bash
или zsh
(с оболочками, отличными от zsh
предположения, что содержимое не содержит байтов NUL):
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"
iconv + голова
Чтобы напечатать первые 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
значения, отличные от 1, до тех пор, пока вы не используете iflag=fullblock
расширение GNU, как это dd
может сделать короткое чтение, если оно читает канал быстрее, чем iconv
заполняет его.
cut
прежнему не поддерживает многобайтовые символы. Если бы это было так, вы могли бы сделатьcut -zc-1234 | tr -d '\0'
.