Commande Linux (comme cat) pour lire une quantité spécifiée de caractères

120

Existe-t-il une commande comme catsous Linux qui peut renvoyer une quantité spécifiée de caractères à partir d'un fichier?

par exemple, j'ai un fichier texte comme:

Hello world
this is the second line
this is the third line

Et je veux quelque chose qui renverrait les 5 premiers caractères, qui serait "bonjour".

Merci

pbreault
la source
Notez qu'aucune des réponses données ne consomme seulement N octets d'un flux. Par exemple: mkfifo /tmp/test.fifo; echo "hello world">/tmp/test.fifo & head -c 5 /tmp/test.fifoconsomme aussi " world\n"ce qui est perdu à jamais.
Yeti

Réponses:

192

head fonctionne aussi:

head -c 100 file  # returns the first 100 bytes in the file

.. va extraire les 100 premiers octets et les renvoyer.

Ce qui est bien d'utiliser headpour cela, c'est que la syntaxe des tailcorrespondances:

tail -c 100 file  # returns the last 100 bytes in the file

Vous pouvez les combiner pour obtenir des plages d'octets. Par exemple, pour obtenir les 100 seconds octets d'un fichier, lisez les 200 premiers avec headet utilisez tail pour obtenir les 100 derniers:

head -c 200 file | tail -c 100
Dan
la source
@Miffy: Lisez les 20 premiers octets avec head, puis utilisez tailpour obtenir les 10 derniers, par exemple:head -c 20 file | tail -c 10
Dan
47

Vous pouvez utiliser dd pour extraire des blocs d'octets arbitraires.

Par exemple,

dd skip=1234 count=5 bs=1

copierait les octets 1235 à 1239 de son entrée vers sa sortie, et rejetterait le reste.

Pour obtenir simplement les cinq premiers octets de l'entrée standard, procédez comme suit:

dd count=5 bs=1

Notez que, si vous souhaitez spécifier le nom du fichier d'entrée, dd a une analyse d'argument à l'ancienne, vous feriez donc:

dd count=5 bs=1 if=filename

Notez également que dd annonce verbalement ce qu'il a fait, alors pour le jeter, faites:

dd count=5 bs=1 2>&-

ou

dd count=5 bs=1 2>/dev/null
fcw
la source
2
Je recommande de ne pas utiliser cette solution en général, car cela dd bs=1force dd à lire et à écrire un seul caractère à la fois, ce qui est beaucoup plus lent que headlorsque le nombre est grand. Ce n'est pas perceptible pour count = 5, cependant.
éphémère
2
Qu'en est-il de "dd count = 1 bs = 5"? Cela ferait lire la tête cinq octets en une seule fois. Pourtant, la tête est probablement une solution plus claire.
Ben Combee
1
Merci pour cela - je cherchais en fait un moyen de «couper» un fichier binaire et dd, semble-t-il, fera l'affaire.
sdaau
c'était une bouée de sauvetage sur busybox sans head -cimplémenter l' dd bs=5 count=1approche a fonctionné
Jay Paroline
11

tête :

Nom

head - affiche la première partie des fichiers

Synopsis

head [ OPTION ] ... [ FILE ] ...

La description

Imprimez les 10 premières lignes de chaque FICHIER sur la sortie standard. Avec plus d'un FICHIER, faites précéder chacun d'eux d'un en-tête donnant le nom du fichier. Sans FILE, ou lorsque FILE vaut -, lisez l'entrée standard.

Les arguments obligatoires pour les options longues sont également obligatoires pour les options courtes.
-c , --bytes = [-] N affiche les N premiers octets de chaque fichier; avec le début '-', affiche tous les octets sauf les N derniers de chaque fichier

gimel
la source
3

la tête ou la queue peuvent le faire aussi:

tête -c X

Imprime les X premiers octets (pas nécessairement des caractères s'il s'agit d'un fichier UTF-16) du fichier. tail fera de même, sauf pour les X derniers octets.

Ceci (et coupé) sont portables.

Zathrus
la source
3
head -Line_number file_name | tail -1 |cut -c Num_of_chars

ce script donne le nombre exact de caractères de la ligne et de l'emplacement spécifiques, par exemple:

head -5 tst.txt | tail -1 |cut -c 5-8

donne les caractères de la ligne 5 et les caractères 5 à 8 de la ligne 5,

Remarque : tail -1permet de sélectionner la dernière ligne affichée par la tête.

Vignesh
la source
2

vous pouvez également grep la ligne, puis la couper comme par exemple:

grep nom de fichier 'texte' | coupe -c 1-5

nkr1pt
la source
Cela ne fonctionne pas si le fichier d'entrée est un flux sans fin sans \ n
Ajay Brahmakshatriya
2

Je sais que la réponse est en réponse à une question posée il y a 6 ans ...

Mais j'ai cherché quelque chose de similaire pendant quelques heures, puis j'ai découvert que: cut -c fait exactement cela, avec un bonus supplémentaire que vous pouvez également spécifier un décalage.

cut -c 1-5 retournera Hello et cut -c 7-11 retournera world . Pas besoin d'une autre commande

Bobbyus
la source
2
Tu as raison!. Je voulais juste souligner la possibilité d'une commande unique plus générique qui peut renvoyer du texte depuis le milieu d'un fichier contrairement à head -c ne lira que les caractères de départ, tail -c les derniers caractères. Et sans utiliser grep :).
bobbyus
2

Même si cela a été répondu / accepté il y a des années, la réponse actuellement acceptée n'est correcte que pour les encodages à un octet par caractère comme iso-8859-1, ou pour les sous-ensembles à un octet de jeux de caractères à octets variables (comme les caractères latins dans UTF-8). Même l'utilisation d'épissures multi-octets à la place ne fonctionnerait que pour les encodages multi-octets fixes comme UTF-16. Étant donné que maintenant UTF-8 est en passe de devenir une norme universelle, et lorsque vous examinez cette liste de langues par nombre de locuteurs natifs et cette liste des 30 principales langues par usage natif / secondaire , il est important de souligner un technique simple à octets variable (non basée sur les octets), utilisant cut -cet tr/ sedavec des classes de caractères.

Comparez ce qui suit qui échoue doublement en raison de deux erreurs / présomptions courantes centrées sur le latin concernant le problème des octets par rapport aux caractères (l'un est headcontre cut, l'autre est [a-z][A-Z]contre [:upper:][:lower:]):

$ printf 'Πού μπορώ να μάθω σανσκριτικά;\n' | \
$     head -c 1 | \
$     sed -e 's/[A-Z]/[a-z]/g'
[[unreadable binary mess, or nothing if the terminal filtered it]]

à ceci (note: cela a bien fonctionné sur FreeBSD, mais les deux cutet trsur GNU / Linux ont toujours mutilé le grec en UTF-8 pour moi cependant):

$ printf 'Πού μπορώ να μάθω σανσκριτικά;\n' | \
$     cut -c 1 | \
$     tr '[:upper:]' '[:lower:]'
π

Une autre réponse plus récente avait déjà proposé "couper", mais uniquement à cause du problème secondaire qu'il peut être utilisé pour spécifier des décalages arbitraires, pas à cause du problème directement pertinent entre les caractères et les octets.

Si vous cutne gérez pas -ccorrectement les encodages en octets variables, pour "les premiers Xcaractères" (remplacez-les Xpar votre numéro), vous pouvez essayer:

  • sed -E -e '1 s/^(.{X}).*$/\1/' -e q - qui se limite cependant à la première ligne
  • head -n 1 | grep -E -o '^.{X}' - qui est limité à la première ligne et enchaîne cependant deux commandes
  • dd - qui a déjà été suggéré dans d'autres réponses, mais qui est vraiment encombrant
  • Un sedscript compliqué avec un tampon de fenêtre coulissant pour gérer des caractères répartis sur plusieurs lignes, mais qui est probablement plus encombrant / fragile que d'utiliser simplement quelque chose commedd

Si votre trne gère pas correctement les classes de caractères avec des codages d'octets variables, vous pouvez essayer:

  • sed -E -e 's/[[:upper:]]/\L&/g (Spécifique à GNU)
Rowanthorpe
la source
désolé, mais ça ne marche pas ici ... printf 'Πού ' | cut -c 1retourne juste du charabia ... ça se comporte comme 'head'
LEo
selon la documentation en ligne, il n'est pas encore disponible: "Sélectionnez pour imprimer uniquement les caractères aux positions listées dans la liste de caractères. Identique à -b pour le moment, mais l'internationalisation va changer cela." [ gnu.org/software/coreutils/manual/html_node/…
LEo
@LEo Sur la base du lien dans votre deuxième commentaire, il semble que vous utilisez un système d'exploitation basé sur GNU, vraisemblablement GNU / Linux, donc dans ce cas, c'est attendu - je le mentionne à la fin de ma réponse. Cela fonctionnait alors (et fonctionne maintenant) pour moi sur FreeBSD (et probablement sur certains autres OS) mais ne fonctionnait pas (et ne fonctionne pas encore) sous GNU / Linux, pour ce cas, j'ai mentionné les méthodes alternatives à la fin. Personnellement, je ne peux pas attendre que quelqu'un trouve et offre du temps libre pour faire l'internationalisation nécessaire pour que l'ensemble d'outils GNU fonctionne aussi bien que les autres à cet égard.
rowanthorpe
0

Voici un script simple qui se termine en utilisant l' ddapproche mentionnée ici:

extract_chars.sh

#!/usr/bin/env bash

function show_help()
{
  IT="
extracts characters X to Y from stdin or FILE
usage: X Y {FILE}

e.g. 

2 10 /tmp/it     => extract chars 2-10 from /tmp/it
EOF
  "
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$1" ]
then
  show_help
fi

FROM=$1
TO=$2
COUNT=`expr $TO - $FROM + 1`

if [ -z "$3" ]
then
  dd skip=$FROM count=$COUNT bs=1 2>/dev/null
else
  dd skip=$FROM count=$COUNT bs=1 if=$3 2>/dev/null 
fi
Brad Parks
la source