it-swarm-fr.com

Comment obtenir un comportement inverse pour «queue» et «tête»?

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.

57
chrisjlee

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.

59
Stéphane Gimenez

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
3
Steven Monday

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.

3
enzotib
{   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.

2
mikeserv

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}'
1

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)
1
sokoban

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)

0
Abe

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!

0
spectrum

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

/ 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"
0
Mathieu Coavoux