Sie können dieses awk verwenden:
awk -v s='2,4' 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' file
two
four
Über ein separates Skript lines.sh
:
#!/bin/bash
awk -v s="$1" 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' "$2"
Geben Sie dann Ausführungsberechtigungen:
chmod +x lines.sh
Und nennen Sie es als:
./lines.sh '2,4' 'test.txt'
Versuchen Sie es mit sed
:
sed -n '2p; 4p' inputFile
-n
sagt sed
um die Ausgabe zu unterdrücken, sondern für die Zeilen 2
und 4
, die p
(print) Befehl wird verwendet, um diese Zeilen zu drucken.
Sie können auch Bereiche verwenden, z. B.:
sed -n '2,4p' inputFile
Zwei reine Bash-Versionen. Da Sie nach allgemeinen und wiederverwendbaren Lösungen suchen, können Sie sich auch ein wenig Mühe geben. (Siehe auch letzten Abschnitt).
Version 1
Dieses Skript schlürft die gesamte Standardeingabe in ein Array (unter Verwendung von mapfile
, also ziemlich effizient) und druckt dann die Zeilen, die in seinen Argumenten angegeben sind. Bereiche sind gültig, z. B.
1-4 # for lines 1, 2, 3 and 4
3- # for everything from line 3 till the end of the file
Sie können diese durch Leerzeichen oder Kommas trennen. Die Zeilen werden genau in der Reihenfolge ausgegeben, in der die Argumente angegeben werden:
lines 1 1,2,4,1-3,4- 1
wird Zeile 1 zweimal drucken, dann Zeile 2, dann Zeile 4, dann Zeile 1, 2 und 3, dann alles von Zeile 4 bis zum Ende und schließlich wieder Zeile 1.
Bitte schön:
#!/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:Es ist wirklich cool.
- Con:Muss den gesamten Stream in den Speicher lesen. Nicht geeignet für unendliche Streams.
Version 2
Diese Version adressiert das frühere Problem der unendlichen Streams. Aber Sie verlieren die Möglichkeit, Zeilen zu wiederholen und neu anzuordnen.
Das Gleiche gilt, Bereiche sind erlaubt:
lines 1 1,4-6 9-
druckt die Zeilen 1, 4, 5, 6, 9 und alles bis zum Ende. Wenn die Zeilenmenge begrenzt ist, wird beendet, sobald die letzte Zeile gelesen wurde.
#!/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:Es ist wirklich cool und liest nicht den vollständigen Stream im Speicher.
- Nachteil:Zeilen können nicht wie in Version 1 wiederholt oder neu angeordnet werden. Geschwindigkeit ist nicht ihre Stärke.
Weitere Gedanken
Wenn Sie wirklich ein großartiges allgemeines Skript wollen, das das tut, was Version 1 und Version 2 tun, und mehr, sollten Sie unbedingt eine andere Sprache verwenden, z. B. Perl:Sie werden viel gewinnen (insbesondere Geschwindigkeit)! Sie werden in der Lage sein, nette Optionen zu haben, die viele viel coolere Sachen machen. Es könnte sich auf lange Sicht lohnen, da Sie ein allgemeines und wiederverwendbares Skript wünschen. Vielleicht haben Sie sogar ein Skript, das E-Mails liest!
Haftungsausschluss. Ich habe diese Skripte nicht gründlich überprüft ... also hüte dich vor Fehlern!