Puoi usare questo awk:
awk -v s='2,4' 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' file
two
four
Tramite uno script separato lines.sh
:
#!/bin/bash
awk -v s="$1" 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' "$2"
Quindi dai i permessi di esecuzione:
chmod +x lines.sh
E chiamalo come:
./lines.sh '2,4' 'test.txt'
Prova sed
:
sed -n '2p; 4p' inputFile
-n
dice sed
per sopprimere l'output, ma per le righe 2
e 4
, il p
Il comando (print) viene utilizzato per stampare queste righe.
Puoi anche utilizzare intervalli, ad esempio:
sed -n '2,4p' inputFile
Due versioni Bash pure. Dal momento che stai cercando soluzioni generali e riutilizzabili, potresti anche impegnarti un po '. (Vedi anche l'ultima sezione).
Versione 1
Questo script inserisce l'intero stdin in un array (usando mapfile
, quindi è piuttosto efficiente) e quindi stampa le righe specificate sui suoi argomenti. Gli intervalli sono validi, ad esempio,
1-4 # for lines 1, 2, 3 and 4
3- # for everything from line 3 till the end of the file
Puoi separarli con spazi o virgole. Le righe vengono stampate esattamente nell'ordine in cui sono forniti gli argomenti:
lines 1 1,2,4,1-3,4- 1
stamperà la riga 1 due volte, quindi la riga 2, quindi la riga 4, quindi le righe 1, 2 e 3, quindi tutto dalla riga 4 fino alla fine e infine di nuovo la riga 1.
Ecco qua:
#!/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:è davvero fantastico.
- Contro:necessita di leggere l'intero flusso in memoria. Non adatto a flussi infiniti.
Versione 2
Questa versione risolve il precedente problema dei flussi infiniti. Ma perderai la possibilità di ripetere e riordinare le righe.
Stessa cosa, gli intervalli sono consentiti:
lines 1 1,4-6 9-
stamperà le righe 1, 4, 5, 6, 9 e tutto fino alla fine. Se l'insieme di righe è delimitato, esce non appena viene letta l'ultima riga.
#!/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:è davvero fantastico e non legge l'intero flusso in memoria.
- Contro:impossibile ripetere o riordinare le righe come nella versione 1. La velocità non è il suo punto di forza.
Ulteriori riflessioni
Se vuoi davvero uno script generale fantastico che faccia ciò che fa la versione 1 e la versione 2, e altro ancora, dovresti assolutamente considerare l'utilizzo di un altro linguaggio, ad esempio Perl:guadagnerai molto (in particolare velocità)! sarai in grado di avere belle opzioni che faranno molte cose molto più interessanti. Potrebbe valerne la pena a lungo termine, poiché desideri uno script generale e riutilizzabile. Potresti persino ritrovarti con uno script che legge le email!
Esclusione di responsabilità. Non ho controllato a fondo questi script... quindi attenzione ai bug!