Vous pouvez utiliser ce awk :
awk -v s='2,4' 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' file
two
four
Via un script séparé lines.sh
:
#!/bin/bash
awk -v s="$1" 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' "$2"
Donnez ensuite les autorisations d'exécution :
chmod +x lines.sh
Et appelez-le comme :
./lines.sh '2,4' 'test.txt'
Essayez sed
:
sed -n '2p; 4p' inputFile
-n
dit sed
pour supprimer la sortie, mais pour les lignes 2
et 4
, le p
La commande (print) est utilisée pour imprimer ces lignes.
Vous pouvez également utiliser des plages, par exemple :
sed -n '2,4p' inputFile
Deux versions pures de Bash. Puisque vous recherchez des solutions générales et réutilisables, autant y mettre un peu d'effort. (Voir également la dernière section).
Version 1
Ce script transforme tout le stdin dans un tableau (en utilisant mapfile
, donc c'est plutôt efficace) puis imprime les lignes spécifiées sur ses arguments. Les plages sont valides, par exemple,
1-4 # for lines 1, 2, 3 and 4
3- # for everything from line 3 till the end of the file
Vous pouvez les séparer par des espaces ou des virgules. Les lignes sont imprimées exactement dans l'ordre dans lequel les arguments sont donnés :
lines 1 1,2,4,1-3,4- 1
imprimera la ligne 1 deux fois, puis la ligne 2, puis la ligne 4, puis les lignes 1, 2 et 3, puis tout de la ligne 4 jusqu'à la fin, et enfin, la ligne 1 à nouveau.
Voilà :
#!/bin/bash
lines=()
# Slurp stdin in array
mapfile -O1 -t lines
# Arguments:
IFS=', ' read -ra args <<< "$*"
for arg in "${args[@]}"; do
if [[ $arg = +([[:digit:]]) ]]; then
arg=$arg-$arg
fi
if [[ $arg =~ ([[:digit:]]+)-([[:digit:]]*) ]]; then
((from=10#${BASH_REMATCH[1]}))
((to=10#${BASH_REMATCH[2]:-$((${#lines[@]}))}))
((from==0)) && from=1
((to>=${#lines[@]})) && to=${#lines[@]}
((from<=to)) || printf >&2 'Argument %d-%d: lines not in increasing order' "$from" "$to"
for((i=from;i<=to;++i)); do
printf '%s\n' "${lines[i]}"
done
else
printf >&2 "Error in argument \`%s'.\n" "$arg"
fi
done
- Pro :C'est vraiment cool.
- Inconvénient :Nécessite de lire le flux entier dans la mémoire. Ne convient pas aux flux infinis.
Version 2
Cette version résout le problème précédent des flux infinis. Mais vous perdrez la possibilité de répéter et de réorganiser les lignes.
Idem, les plages sont autorisées :
lines 1 1,4-6 9-
imprimera les lignes 1, 4, 5, 6, 9 et tout jusqu'à la fin. Si l'ensemble de lignes est borné, quitte dès que la dernière ligne est lue.
#!/bin/bash
lines=()
tillend=0
maxline=0
# Process arguments
IFS=', ' read -ra args <<< "[email protected]"
for arg in "${args[@]}"; do
if [[ $arg = +([[:digit:]]) ]]; then
arg=$arg-$arg
fi
if [[ $arg =~ ([[:digit:]]+)-([[:digit:]]*) ]]; then
((from=10#${BASH_REMATCH[1]}))
((from==0)) && from=1
((tillend && from>=tillend)) && continue
if [[ -z ${BASH_REMATCH[2]} ]]; then
tillend=$from
continue
fi
((to=10#${BASH_REMATCH[2]}))
if ((from>to)); then
printf >&2 "Invalid lines order: %s\n" "$arg"
exit 1
fi
((maxline<to)) && maxline=$to
for ((i=from;i<=to;++i)); do
lines[i]=1
done
else
printf >&2 "Invalid argument \`%s'\n" "$arg"
exit 1
fi
done
# If nothing to read, exit
((tillend==0 && ${#lines[@]}==0)) && exit
# Now read stdin
linenb=0
while IFS= read -r line; do
((++linenb))
((tillend==0 && maxline && linenb>maxline)) && exit
if [[ ${lines[linenb]} ]] || ((tillend && linenb>=tillend)); then
printf '%s\n' "$line"
fi
done
- Pro :c'est vraiment cool et ne lit pas le flux complet en mémoire.
- Inconvénient :Impossible de répéter ou de réorganiser les lignes comme dans la version 1. La vitesse n'est pas son point fort.
Autres réflexions
Si vous voulez vraiment un script général génial qui fasse ce que font la version 1 et la version 2, et plus encore, vous devriez certainement envisager d'utiliser un autre langage, par exemple Perl :vous gagnerez beaucoup (en particulier en vitesse) ! vous pourrez avoir de belles options qui feront beaucoup de choses beaucoup plus cool. Cela pourrait en valoir la peine à long terme, car vous voulez un script général et réutilisable. Vous pourriez même finir par avoir un script qui lit les e-mails !
Avis de non-responsabilité. Je n'ai pas bien vérifié ces scripts... alors méfiez-vous des bugs !