Comment obtenir la première ligne d'un fichier dans un script bash?

249

Je dois mettre dans une variable bash la première ligne d'un fichier. Je suppose que c'est avec la commande grep, mais est-il possible de restreindre le nombre de lignes?

Neuquino
la source

Réponses:

396

headprend les premières lignes d'un fichier, et le -nparamètre peut être utilisé pour spécifier le nombre de lignes à extraire:

line=$(head -n 1 filename)
qch
la source
3
Beaucoup plus de frais généraux que l' readapproche. $()bifurque un sous-shell, et l'utilisation d'une commande externe ( n'importe quelle commande externe) signifie que vous appelez execve(), en invoquant l'éditeur de liens et le chargeur (s'il utilise des bibliothèques partagées, ce qui est généralement le cas), etc.
Charles Duffy
2
Cela pourrait être encore plus court:line="$(head -1 FILENAME)"
nikolay
3
Et aussi:line=`head -1 FILENAME`
Shai Alon
Le backticks autour de l' head...ouverture est-il un sous-shell $()?
Jaime Hablutzel
@JaimeHablutzel Oui, c'est la même chose, bien que je trouve personnellement que la $()syntaxe est plus facile à voir et privilégie la clarté par rapport à la justesse absolue. gnu.org/software/bash/manual/html_node/…
Joseph Sikorski
61

pour lire la première ligne en utilisant bash, utilisez l' readinstruction. par exemple

read -r firstline<file

firstline sera votre variable (pas besoin de l'attribuer à une autre)

ghostdog74
la source
1
@sorin, cat ... | read VARéchouera dans la plupart des shells (tous sauf zshpour autant que je sache) car chacun des composants d'un tuyau fonctionnera dans des sous-shells séparés. Signification qui $VARsera définie dans le sous-shell (qui cesse d'exister dès que le pipeline a terminé son exécution) plutôt que dans le shell appelant. Vous pouvez contourner cela avec read VAR <<EOF\n$(cat ...)\nEOF(où chacun \nest une nouvelle ligne).
zrajm
@sorin, catest purement aérien; beaucoup plus efficace read -r var <fileque de cat file | readtoute façon, même si ce dernier n'a pas échoué pour les raisons décrites dans BashFAQ # 24 .
Charles Duffy
... si vous dirigez quelque chose de plus complexe cat, alorsread -r var < <(otherprog ...)
Charles Duffy
14

Cela suffit et stocke la première ligne de filenamedans la variable $line:

read -r line < filename

J'aime aussi awkpour ça:

awk 'NR==1 {print; exit}' file

Pour stocker la ligne elle-même, utilisez la var=$(command)syntaxe. Dans ce cas line=$(awk 'NR==1 {print; exit}' file),.

Ou même sed:

sed -n '1p' file

Avec l'équivalent line=$(sed -n '1p' file).


Voir un exemple lorsque nous alimentons le readavec seq 10, c'est-à-dire une séquence de nombres de 1 à 10:

$ read -r line < <(seq 10) 
$ echo "$line"
1

$ line=$(awk 'NR==1 {print; exit}' <(seq 10))
$ echo "$line"
1
fedorqui 'SO arrête de nuire'
la source
1
sed '1!d;q'(ou sed -n '1p;q') imitera votre awklogique et empêchera la lecture du fichier. Parce que nous ne voulons que la première ligne, nous pouvons alternativement tricher avec sed qou awk '1;{exit}'ou même grep -m1 ^(moins de code, même logique essentielle). (Ce n'est pas une réponse à l'enquête sur les votes négatifs.)
Adam Katz
@AdamKatz c'est un très bel ensemble de façons, merci! Je trouve celui avec greptrès intelligent. On peut bien sûr dire aussi head -n 1 file.
fedorqui 'SO arrête de nuire'
Oui, ce head -n1sera plus rapide (binaire plus petit à charger) et readplus rapide (pas de binaire à charger, c'est une fonction intégrée). J'aime particulièrement grep -m1 --color .lorsque j'imprime la première ligne, car elle colorera également la ligne, ce qui la rend idéale pour les en-têtes de tableau.
Adam Katz
12
line=$(head -1 file)

Fonctionnera bien. (Comme réponse précédente). Mais

line=$(read -r FIRSTLINE < filename)

sera légèrement plus rapide que la readcommande bash intégrée.

jackbot
la source
21
La deuxième méthode ne fonctionne pas comme écrite, car readn'imprime rien (donc linese vide), et s'exécute également dans un sous-shell (est donc FIRSTLINEdéfini sur la première ligne, mais uniquement dans le sous-shell, il n'est donc pas disponible par la suite). Solution: utilisez simplementread -r line <filename
Gordon Davisson
5

Juste echola première liste de votre fichier source dans votre fichier cible.

echo $(head -n 1 source.txt) > target.txt
openwonk
la source
3
Pour qui head -n 1 source.txt > target.txtaccomplira exactement la même chose.
YoYo
4

La question n'a pas demandé laquelle est la plus rapide, mais pour ajouter à la réponse sed, -n '1p' fonctionne mal car l'espace de motif est toujours analysé sur les gros fichiers. Par curiosité, j'ai découvert que la «tête» l'emporte de justesse sur sed:

# best:
head -n1 $bigfile >/dev/null

# a bit slower than head (I saw about 10% difference):
sed '1q' $bigfile >/dev/null

# VERY slow:
sed -n '1p' $bigfile >/dev/null
Neil McGill
la source