Alguns sistemas possuem um comando truncate
que trunca arquivos para um número de bytes (não caracteres).
Eu não conheço nenhum que seja truncado para vários caracteres, embora você possa recorrer a perl
, que é instalado por padrão na maioria dos sistemas:
perl
perl -Mopen=locale -ne '
BEGIN{$/ = 34} truncate STDIN, tell STDIN; last' <> "$file"
-
Com
-Mopen=locale
, usamos a noção de localidade de quais caracteres são (portanto, em locales que usam o conjunto de caracteres UTF-8, são caracteres codificados em UTF-8). Substitua por-CS
se quiser que a E / S seja decodificada / codificada em UTF-8, independentemente do conjunto de caracteres da localidade. -
$/ = 34
: definimos o separador de registro como uma referência a um inteiro, que é uma forma de especificar registros de tamanho fixo (em número de caracteres ). -
depois de ler o primeiro registro, truncamos stdin no lugar (assim no final do primeiro registro) e saímos.
sed GNU
Com o GNU sed
, você poderia fazer (assumindo que o arquivo não contenha caracteres NUL ou seqüências de bytes que não formam caracteres válidos - ambos devem ser verdadeiros para arquivos de texto):
sed -Ez -i -- 's/^(.{1234}).*//' "$file"
Mas isso é muito menos eficiente, pois lê o arquivo inteiro e armazena todo na memória, e escreve uma nova cópia.
GNU awk
Mesmo com o GNU awk
:
awk -i inplace -v RS='^$' -e '{printf "%s", substr($0, 1, 1234)}' -E /dev/null "$file"
-
-e code -E /dev/null "$file"
sendo uma maneira de passar nomes de arquivos arbitrários paragawk
-
RS='^$'
: modo de suspensão .
Builtins de shell
Com ksh93
, bash
ou zsh
(com shells diferentes de zsh
, supondo que o conteúdo não contenha bytes NUL):
content=$(cat < "$file" && echo .) &&
content=${content%.} &&
printf %s "${content:0:1234}" > "$file"
com zsh
:
read -k1234 -u0 s < $file &&
printf %s $s > $file
Ou:
zmodload zsh/mapfile
mapfile[$file]=${mapfile[$file][1,1234]}
Com ksh93
ou bash
(tenha cuidado com é falso para caracteres de múltiplos bytes em várias versões de bash
):
IFS= read -rN1234 s < "$file" &&
printf %s "$s" > "$file"
ksh93
também pode truncar o arquivo em vez de reescrevê-lo com o operador de redirecionamento <>;
:
IFS= read -rN1234 0<>; "$file"
íconev + cabeça
Para imprimir os primeiros 1234 caracteres, outra opção poderia ser converter em uma codificação com um número fixo de bytes por caractere, como UTF32BE
/ UCS-4
:
iconv -t UCS-4 < "$file" | head -c "$((1234 * 4))" | iconv -f UCS-4
head -c
não é padrão, mas é bastante comum. Um equivalente padrão seria dd bs=1 count="$((1234 * 4))"
, mas seria menos eficiente, pois leria a entrada e gravaria a saída um byte de cada vez¹. iconv
é um comando padrão, mas os nomes de codificação não são padronizados, portanto, você pode encontrar sistemas sem UCS-4
Notas
Em qualquer caso, embora a saída tenha no máximo 1234 caracteres, pode acabar não sendo um texto válido, já que possivelmente terminaria em uma linha não delimitada.
Observe também que enquanto essas soluções não cortam texto no meio de um personagem, elas podem quebrá-lo no meio de um grapheme , como é
expresso como U + 0065 U + 0301 (a e
seguido de um sotaque agudo de combinação), ou grafemas sílabas de Hangul nas suas formas decompostas.
¹ e na entrada pipe você não pode usar bs
valores além de 1 de forma confiável a menos que você use a extensão iflag=fullblock
GNU, pois dd
poderia fazer leituras curtas se ler o pipe mais rápido que iconv
preenche