Algunos sistemas tienen un truncate
comando que trunca los archivos a una cantidad de bytes (no caracteres).
No conozco ninguno que se trunca a varios caracteres, aunque podría recurrir al perl
que está instalado de forma predeterminada en la mayoría de los sistemas:
perl
perl -Mopen=locale -ne '
BEGIN{$/ = \1234} truncate STDIN, tell STDIN; last' <> "$file"
Con -Mopen=locale
, usamos la noción de la configuración regional de qué caracteres son (por lo tanto, en las configuraciones regionales que usan el juego de caracteres UTF-8, eso es caracteres codificados UTF-8). Reemplace con -CS
si desea que la E / S se decodifique / codifique en UTF-8, independientemente del conjunto de caracteres del entorno local.
$/ = \1234
: configuramos el separador de registros como una referencia a un entero, que es una forma de especificar registros de longitud fija (en número de caracteres ).
luego, al leer el primer registro, truncamos stdin en su lugar (al final del primer registro) y salimos.
GNU sed
Con GNU sed
, podría hacerlo (suponiendo que el archivo no contenga caracteres NUL o secuencias de bytes que no formen caracteres válidos, los cuales deberían ser ciertos para los archivos de texto):
sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
Pero eso es mucho menos eficiente, ya que lee el archivo completo y lo almacena completo en la memoria, y escribe una nueva copia.
GNU awk
Lo mismo con GNU awk
:
awk -i inplace -v RS='^$' -e '{printf "%s", substr($0, 1, 1234)}' -E /dev/null "$file"
-e code -E /dev/null "$file"
siendo una forma de pasar nombres de archivos arbitrarios a gawk
RS='^$'
: modo sorber .
Conchas incorporadas
Con ksh93
, bash
o zsh
(con conchas distintos zsh
, suponiendo que el contenido no contiene NUL bytes):
content=$(cat < "$file" && echo .) &&
content=${content%.} &&
printf %s "${content:0:1234}" > "$file"
Con zsh
:
read -k1234 -u0 s < $file &&
printf %s $s > $file
O:
zmodload zsh/mapfile
mapfile[$file]=${mapfile[$file][1,1234]}
Con ksh93
o bash
(cuidado , es falso para los caracteres de varios bytes en varias versiones debash
):
IFS= read -rN1234 s < "$file" &&
printf %s "$s" > "$file"
ksh93
También puede truncar el archivo en su lugar en lugar de reescribirlo con su <>;
operador de redirección:
IFS= read -rN1234 0<>; "$file"
iconv + cabeza
Para imprimir los primeros 1234 caracteres, otra opción podría ser convertir a una codificación con un número fijo de bytes por carácter como UTF32BE
/ UCS-4
:
iconv -t UCS-4 < "$file" | head -c "$((1234 * 4))" | iconv -f UCS-4
head -c
No es estándar, sino bastante común. Un equivalente estándar sería dd bs=1 count="$((1234 * 4))"
pero sería menos eficiente, ya que leería la entrada y escribiría la salida un byte a la vez¹. iconv
es un comando estándar pero los nombres de codificación no están estandarizados, por lo que puede encontrar sistemas sinUCS-4
Notas
En cualquier caso, aunque la salida tendría como máximo 1234 caracteres, puede terminar siendo texto no válido, ya que posiblemente terminaría en una línea no delimitada.
También tenga en cuenta que si bien esas soluciones no cortarían el texto en el medio de un carácter, podrían romperlo en el medio de un grafema , como un é
expresado como U + 0065 U + 0301 ( e
seguido de un acento agudo combinado), o grafemas de sílabas Hangul en sus formas descompuestas.
¹ y en la entrada de tubería no puede usar bs
valores distintos de 1 de manera confiable a menos que use la iflag=fullblock
extensión GNU, ya que dd
podría hacer lecturas cortas si lee la tubería más rápido de lo que la iconv
llena
cut
todavía no admite caracteres de varios bytes. Si lo hiciera, podrías hacerlocut -zc-1234 | tr -d '\0'
.