web-dev-qa-db-fra.com

Imprimez des lignes impaires imprimées, des lignes d'impression même

Je souhaite imprimer les lignes impairs numérotées et numérotées à partir de fichiers.

J'ai trouvé ce script shell qui utilise Echo.

#!/bin/bash
# Write a Shell script that, given a file name as the argument will write
# the even numbered line to a file with name evenfile and odd numbered lines
# in a text file called oddfile.
# -------------------------------------------------------------------------
# Copyright (c) 2001 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft Shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------

file=$1
counter=0

eout="evenfile.$$" # even file name
oout="oddfile.$$" # odd file name

if [ $# -eq 0 ]
then
    echo "$(basename $0) file"
    exit 1
fi

if [ ! -f $file ]
then
    echo "$file not a file"
    exit 2
fi

while read line
do
    # find out odd or even line number
    isEvenNo=$( expr $counter % 2 )

    if [ $isEvenNo -ne 0 ]
    then
        # even match
        echo $line >> $eout
    else
        # odd match
        echo $line >> $oout
    fi
    # increase counter by 1
    (( counter ++ ))
done < $file
echo "Even file - $eout"
echo "Odd file - $oout"

Mais n'est-il pas un moyen de le faire en une seule ligne?

Oui, utilisez awk, j'ai lu.

Lignes même numérotées:

awk 'NR % 2' filename

lignes impaires:

awk 'NR % 2 == 1' filename

Mais ça ne marche pas pour moi. Les deux produisent la même sortie, selon DIFF. Par rapport au fichier d'origine, ils sont à la fois la moitié aussi longue, et ils contiennent tous deux les lignes impairées. Est-ce que je fais quelque chose de mal?

21
ixtmixilix

Comme vous avez demandé "en une ligne":

awk '{print>sprintf("%sfile.%d",NR%2?"odd":"even",PROCINFO["pid"])}' filename

Notez que la majeure partie du code est due à votre choix de nom de fichier de sortie de sortie. Sinon, le code suivant suffirait à mettre des lignes impaires dans "Line-1" et même des lignes dans "Line-0":

awk '{print>"line-"NR%2}' filename
12
manatwork

Je préfère être compatible Posix, dans la mesure du possible, je pensais que je postirais cette méthode alternative. Je les utilise souvent pour mangler du texte avant xargs pipelines.

Imprimer même lignes numérotées,

sed -n 'n;p'

Imprimer des lignes numérotées impair,

sed -n 'p;n'

Bien que j'utilise souvent awk, il est surchargé pour ce type de tâche.

27
J. M. Becker

Pour même des chiffres, le code devrait être

awk 'NR%2==0' filename

et pour les nombres impairs

awk 'NR%2==1' filename
12
Neel

Vous pouvez le faire avec une seule invocation sed, aucun besoin de lire deux fois le fichier:

sed '$!n
w even
d' infile > odd

ou, si vous préférez en une ligne:

sed -e '$!n' -e 'w even' -e d infile > odd

Notez que ceux-ci ne donneront pas le résultat attendu si un fichier ne contient qu'une seule ligne (la ligne sera wRitten to even au lieu de odd comme le premier n n'est pas exécuté). Pour éviter cela, ajoutez une condition:

sed -e '$!n' -e '1!{w even' -e 'd}' infile > odd

Comment ça fonctionne ? Eh bien, il utilise trois commandes sed:
[.____] n - sinon sur la dernière ligne Imprimer L'espace motif à stdout (qui est redirigé vers le fichier odd), Remplacez-le par la ligne suivante (maintenant, il traite une ligne pair) et continuez à exécuter les commandes restantes.
[.____] w - Ajoutez l'espace de motif au fichier even
[.____] d - Supprimer l'espace de modèle actuel et redémarrez le cycle - l'effet secondaire de ceci est que sed n'imprimera jamais l'espace motif car il n'atteint jamais la fin du script

En d'autres termes, n est exécuté uniquement sur des lignes impaires et w et d sont exécutés uniquement sur des lignes même. sed _ N'arrive jamais à autopret à moins que je dise, comme je l'ai dit, l'entrée consiste en une seule ligne.

2
don_crissti

J'irais avec Perl parce que j'aime Perl:

Perl -pe 'BEGIN{open($e,">even_lines");open($o,">odd_lines")} $. % 2 ?select $o:select $e;'

Utilise le fait que -p Imprime implicitement, reproduire comment sed fonctionne - et nous utilisons select pour choisir la poignée de fichier auquel elle écrit.

0
Sobrique

Essaye ça:

awk '{if(NR%2){print $0 > "odd.file"}else{print $0 > "even.file"}}' filename
0
renma