Alguns sistemas possuem um truncate
comando que trunca arquivos para um número de bytes (não caracteres).
Não conheço nenhum que trunque para vários caracteres, embora você possa recorrer ao perl
que está instalado por padrão na maioria dos sistemas:
perl
perl -Mopen=locale -ne '
BEGIN{$/ = \1234} truncate STDIN, tell STDIN; last' <> "$file"
Com -Mopen=locale
, usamos a noção de localidade do que são caracteres (portanto, em localidades que usam o conjunto de caracteres UTF-8, são caracteres codificados em UTF-8). Substitua por -CS
se desejar que a E / S seja decodificada / codificada em UTF-8, independentemente do conjunto de caracteres da localidade.
$/ = \1234
: definimos o separador de registros como uma referência a um número inteiro, que é uma maneira de especificar registros de comprimento fixo (em número de caracteres ).
depois de ler o primeiro registro, truncamos o stdin no lugar (portanto, no final do primeiro registro) e saímos.
GNU sed
Com o GNU sed
, você pode fazer (supondo que o arquivo não contenha caracteres NUL ou seqüências de bytes que não formem caracteres válidos - os quais devem ser verdadeiros para arquivos de texto):
sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
Mas isso é muito menos eficiente, pois ele lê o arquivo na íntegra, armazena-o inteiro na memória e grava uma nova cópia.
GNU awk
O 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 para gawk
RS='^$'
: modo slurp .
Shell builtins
Com ksh93
, bash
ou zsh
(com shells diferentes de zsh
, assumindo que o conteúdo não contenha NUL bytes):
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
(cuidado , é falso para caracteres de vários bytes em várias versões dobash
):
IFS= read -rN1234 s < "$file" &&
printf %s "$s" > "$file"
ksh93
também pode truncar o arquivo no lugar em vez de reescrevê-lo com seu <>;
operador de redirecionamento:
IFS= read -rN1234 0<>; "$file"
iconv + cabeça
Para imprimir os primeiros 1234 caracteres, outra opção pode 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 gravava 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 semUCS-4
Notas
De qualquer forma, embora a saída tenha no máximo 1234 caracteres, pode acabar não sendo um texto válido, pois possivelmente terminaria em uma linha não delimitada.
Observe também que, embora essas soluções não cortem texto no meio de um caractere, elas podem quebrá-lo no meio de um grafema , como um é
expresso como U + 0065 U + 0301 (a e
seguido de um sotaque agudo combinado), ou sílaba de Hangul nas formas decompostas.
¹ e na entrada do tubo, você não pode usar bs
valores diferentes de 1 com confiabilidade, a menos que use a iflag=fullblock
extensão GNU, como dd
poderia fazer leituras curtas se ler o tubo mais rapidamente do que o iconv
preenchê-lo
cut
ainda não suporta caracteres de vários bytes. Se tivesse, você poderia fazercut -zc-1234 | tr -d '\0'
.