Certains systèmes ont une truncate
commande qui tronque les fichiers en un certain nombre d' octets (pas de caractères).
Je n'en connais aucun qui soit tronqué à un certain nombre de caractères, bien que vous puissiez recourir à celui perl
qui est installé par défaut sur la plupart des systèmes:
perl
perl -Mopen=locale -ne '
BEGIN{$/ = \1234} truncate STDIN, tell STDIN; last' <> "$file"
Avec -Mopen=locale
, nous utilisons la notion locale de ce que sont les caractères (donc dans les locales utilisant le jeu de caractères UTF-8, il s'agit de caractères encodés UTF-8). Remplacez par -CS
si vous voulez que les E / S soient décodées / encodées en UTF-8 quel que soit le jeu de caractères des paramètres régionaux.
$/ = \1234
: nous définissons le séparateur d'enregistrement sur une référence à un entier qui est un moyen de spécifier des enregistrements de longueur fixe (en nombre de caractères ).
puis à la lecture du premier enregistrement, nous tronquons stdin en place (donc à la fin du premier enregistrement) et sortons.
GNU sed
Avec GNU sed
, vous pourriez faire (en supposant que le fichier ne contient pas de caractères NUL ou des séquences d'octets qui ne forment pas des caractères valides - les deux devraient être vrais pour les fichiers texte):
sed -Ez -i -- 's/^(.{1234}).*/\1/' "$file"
Mais c'est beaucoup moins efficace, car il lit le fichier dans son intégralité et le stocke intégralement en mémoire, et écrit une nouvelle copie.
GNU awk
Même chose avec GNU awk
:
awk -i inplace -v RS='^$' -e '{printf "%s", substr($0, 1, 1234)}' -E /dev/null "$file"
-e code -E /dev/null "$file"
étant un moyen de passer des noms de fichiers arbitraires à gawk
RS='^$'
: mode slurp .
Coques intégrées
Avec ksh93
, bash
ou zsh
(avec des shells autres que zsh
, en supposant que le contenu ne contient pas d'octets NUL):
content=$(cat < "$file" && echo .) &&
content=${content%.} &&
printf %s "${content:0:1234}" > "$file"
Avec zsh
:
read -k1234 -u0 s < $file &&
printf %s $s > $file
Ou:
zmodload zsh/mapfile
mapfile[$file]=${mapfile[$file][1,1234]}
Avec ksh93
ou bash
(attention c'est faux pour les caractères multi-octets dans plusieurs versions debash
):
IFS= read -rN1234 s < "$file" &&
printf %s "$s" > "$file"
ksh93
peut également tronquer le fichier en place au lieu de le réécrire avec son <>;
opérateur de redirection:
IFS= read -rN1234 0<>; "$file"
iconv + tête
Pour imprimer les 1234 premiers caractères, une autre option pourrait être de convertir en un codage avec un nombre fixe d'octets par caractère comme UTF32BE
/ UCS-4
:
iconv -t UCS-4 < "$file" | head -c "$((1234 * 4))" | iconv -f UCS-4
head -c
n'est pas standard, mais assez courant. Un équivalent standard serait dd bs=1 count="$((1234 * 4))"
mais serait moins efficace, car il lirait l'entrée et écrirait la sortie un octet à la fois¹. iconv
est une commande standard mais les noms d'encodage ne sont pas standardisés, vous pouvez donc trouver des systèmes sansUCS-4
Remarques
Dans tous les cas, bien que la sortie contienne au plus 1234 caractères, elle peut finir par ne pas être du texte valide, car elle se terminerait éventuellement par une ligne non délimitée.
Notez également que même si ces solutions ne couperaient pas le texte au milieu d'un caractère, elles pourraient le casser au milieu d'un graphème , comme un é
exprimé sous la forme U + 0065 U + 0301 (un e
suivi d'un accent aigu combiné), ou graphèmes syllabes Hangul dans leurs formes décomposées.
¹ et sur l'entrée de tuyau, vous ne pouvez pas utiliser des bs
valeurs autres que 1 de manière fiable, sauf si vous utilisez l' iflag=fullblock
extension GNU, comme cela dd
pourrait faire de courtes lectures si elle lit le tuyau plus rapidement qu'il ne le iconv
remplit
cut
still ne prend pas en charge les caractères multi-octets. Si c'était le cas, vous pourriez le fairecut -zc-1234 | tr -d '\0'
.