Existe-t-il un moyen de head
/tail
un document et d'obtenir la sortie inverse; parce que vous ne savez pas combien de lignes il y a dans un document?
C'est à dire. Je veux juste tout obtenir, mais les 2 premières lignes de foo.txt
pour ajouter à un autre document.
Vous pouvez l'utiliser pour supprimer les premières deux lignes:
tail -n +3 foo.txt
et ceci pour dépouiller les dernier deux lignes:
head -n -2 foo.txt
(en supposant que le fichier se termine par \n
pour le dernier)
Tout comme pour l'utilisation standard de tail
et head
ces opérations ne sont pas destructrices. Utilisation >out.txt
si vous souhaitez rediriger la sortie vers un nouveau fichier:
tail -n +3 foo.txt >out.txt
Dans le cas out.txt
existe déjà, il écrasera ce fichier. Utilisation >>out.txt
au lieu de >out.txt
si vous préférez que la sortie soit ajoutée à out.txt
.
Si vous voulez toutes les lignes N-1 sauf les premières, appelez tail
avec le nombre de lignes +N
. (Le nombre est le numéro de la première ligne que vous souhaitez conserver, en commençant à 1, c'est-à-dire que +1 signifie commencer en haut, +2 signifie sauter une ligne, etc.).
tail -n +3 foo.txt >>other-document
Il n'y a pas de moyen facile et portable de sauter les N dernières lignes. GNU head
autorise head -n +N
en contrepartie de tail -n +N
. Sinon, si vous avez tac
(par exemple GNU ou Busybox), vous pouvez le combiner avec tail:
tac | tail -n +3 | tac
Portablement, vous pouvez utiliser un filtre awk (non testé):
awk -vskip=2 '{
lines[NR] = $0;
if (NR > skip) print lines[NR-skip];
delete lines[NR-skip];
}'
Si vous souhaitez supprimer les dernières lignes d'un fichier volumineux, vous pouvez déterminer le décalage en octets de la pièce à tronquer, puis effectuer la troncature avec dd
.
total=$(wc -c < /file/to/truncate)
chop=$(tail -n 42 /file/to/truncate | wc -c)
dd if=/dev/null of=/file/to/truncate seek=1 bs="$((total-chop))"
Vous ne pouvez pas tronquer un fichier en place au début, mais si vous devez supprimer les premières lignes d'un énorme fichier, vous pouvez déplacer le conten .
À partir de la page de manuel tail
(c'est-à-dire GNU tail
):
-n, --lines=K
output the last K lines, instead of the last 10; or use -n +K to
output lines starting with the Kth
Par conséquent, les éléments suivants doivent ajouter toutes les lignes, sauf les 2 premières lignes de somefile.txt
À anotherfile.txt
:
tail --lines=+3 somefile.txt >> anotherfile.txt
Pour supprimer les n premières lignes GNU sed peut être utilisé. Par exemple si n = 2
sed -n '1,2!p' input-file
Le !
signifie "exclure cet intervalle". Comme vous pouvez l'imaginer, un résultat plus compliqué peut être obtenu, par exemple
sed -n '3,5p;7p'
qui affichera la ligne 3,4,5,7. Plus de puissance provient de l'utilisation d'expressions régulières au lieu d'adresses.
La limitation est que les numéros de lignes doivent être connus à l'avance.
{ head -n2 >/dev/null
cat >> other_document
} <infile
Si <infile
est un fichier régulier, lseek()
- capable, alors oui, certainement, n'hésitez pas. Ce qui précède est une construction entièrement prise en charge POSIXly.
Tandis que tail -n +4
pour sortir le fichier à partir de la 4ème ligne (toutes sauf les 3 premières lignes) est standard et portable, son homologue head
(head -n -3
, toutes sauf les 3 dernières lignes) ne l'est pas.
Portablement, vous feriez:
sed '$d' | sed '$d' | sed '$d'
Ou:
sed -ne :1 -e '1,3{N;b1' -e '}' -e 'P;N;D'
(sachez que sur certains systèmes où sed
a un espace de motif de taille limitée, qui ne s’adapte pas aux grandes valeurs de n
).
Ou:
awk 'NR>3 {print l[NR%3]}; {l[NR%3]=$0}'
Vous pouvez utiliser diff
pour comparer la sortie de head
/tail
au fichier d'origine, puis supprimer ce qui est le même, obtenant ainsi l'inverse.
diff --unchanged-group-format='' foo.txt <(head -2 foo.txt)
Mon approche est similaire à celle de Gilles mais au lieu de cela, j'inverse simplement le fichier avec cat et pipe avec la commande head.
tac -r thefile.txt | head thisfile.txt (remplace les fichiers)
Solution pour BSD (macOS):
Supprimer les 2 premières lignes:
tail -n $( echo "$(cat foo.txt | wc -l)-2" | bc )
Supprimer les 2 dernières lignes:
head -n $( echo "$(cat foo.txt | wc -l)-2" | bc )
... pas très élégant mais fait le travail!
J'espère que j'ai bien compris votre besoin.
Vous avez plusieurs façons de compléter votre demande:
tail -n$(expr $(cat /etc/passwd|wc -l) - 2) /etc/passwd
Où / etc/passwd est votre fichier
La 2ème solution peut être utile si vous avez un gros fichier:
my1stline=$(head -n1 /etc/passwd)
my2ndline=$(head -n2 /etc/passwd|grep -v "$my1stline")
cat /etc/passwd |grep -Ev "$my1stline|$my2ndline"