
In einem Verzeichnis habe ich eine bestimmte Anzahl von Dateien. Das könnten 53 txt-Dateien sein, aber ich könnte auch 123 Dateien haben. Die Dateien haben verschiedene zufällige Namen, aber alle haben den Datei-Handle.txt
Ich kann mit ls eine Liste aller Dateien abrufen und diese in eine Variable einfügen.
list_of_txt_files=$(ls *.txt)
Ich möchte die Liste jedoch in mehrere einzelne Listen aufteilen, wobei jede Liste nur 10 Elemente enthält. Ein Ordner mit 53 TXT-Dateien sollte mir also 6 Listen liefern. Das sind 5 Listen mit 10 Dateinamen und eine 6. Liste mit 3 Dateinamen. Mein Beispiel mit 123 TXT-Dateien in einem Verzeichnis sollte mir 12 Listen mit 10 Dateinamen und eine 13. Liste mit nur 3 Dateinamen liefern.
In meinem Beispiel mit 53 txt-Dateien: Liste Nr. 1 würde die erste bis zur zehnten Datei enthalten, und Liste Nr. 2 würde die elfte bis zur zwanzigsten Datei enthalten und so weiter. Ich habe meine Frage vom i-ten bis zum j-ten Element in einer Liste betitelt, da ich annehme, dass andere Leute eine Liste anders aufteilen möchten. Vielleicht von der ersten bis zur 100. Datei in einem Verzeichnis.
Das ultimative Ziel ist, diese Listen in einer for do-Schleife verwenden zu können und den cat-Befehl zu verwenden, um den Inhalt von zehn Dateien pro Liste in eine Datei pro Satz von zehn Dateien zu schreiben – in meinem Beispiel mit 53 Dateien in einem Verzeichnis würde dies 6 Dateien ergeben. Wobei die ersten 5 Dateien den Inhalt der 50 ursprünglichen txt-Dateien enthalten und die 6. Datei den Inhalt der letzten verbleibenden 3 txt-Dateien.
Ich habe überlegt, den Befehl „head“ oder „tail“ zu verwenden, kann aber nicht ganz herausfinden, wie ich für diese beiden Befehle Bereiche angeben kann.
Antwort1
Auf einer Schale mitArrays, verwenden Sie sie. Sagen Sie mit Bash:
$ touch {01..53}
$ files=(*)
$ echo "${files[@]:0:10}"
01 02 03 04 05 06 07 08 09 10
$ for ((i = 0 ; i < ${#files[@]} ; i += 10 )) ; do
echo "${files[@]:i:10}" ;
# or
# cat "${files[@]:i:10}" > set-$(( i / 10 ))
done
01 02 03 04 05 06 07 08 09 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53
DerTeilstringerweiterung(Array-Slice) "${files[@]:i:10}"
wird zu einer Liste von Wörtern und nicht zu einem einzelnen String erweitert, sodass Sie eine Schleife darüber durchführen können:
for f in "${files[@]:i:10}" ; do
somecmd "$f"
done
Nichtdo files=$(ls *.txt)
, das ls
ist hier völlig überflüssig, es ist sowieso die Shell, die das Platzhaltermuster auswertet. Normalerweise speichern Sie das Platzhaltermuster einfach in einer Variable ( pat=*.txt
) und verwenden es (ohne Anführungszeichen), wenn es benötigt wird, oder wenn Sie es in die tatsächlichen Dateinamen erweitern möchten, verwenden Sie echo *.txt
anstelle von ls
. Für die Handhabung von Dateinamenlisten sind Arrays einfach besser, wenn Sie nicht auf eine einfache POSIX-Shell beschränkt sind.
Zum Teilen einer Liste mit head
und tail
müssten Sie etwa Folgendes tun, | head -20 | tail -10
um die Zeilen 11 bis 20 zu erhalten. Oder verwenden Sie sed: | sed -n 11,20p
.
Antwort2
Mit jeder Bourne-ähnlichen Shell (außer der Bourne-Shell, die nicht auf Positionselemente über zugreifen konnte $9
) können Sie Folgendes tun:
set -- *.txt
while [ "$#" -gt 0 ]; do
something with "$1" ${2+"$2"} ${3+"$3"}... ${10+"${10}"}
[ "$#" -gt 10 ] || break
shift 10
done
Mit GNU xargs
und Shells mit Unterstützung für Prozesssubstitution:
xargs -n10 -r0a <(printf '%s\0' *.txt) something with
Mit zsh
:
files=(*.txt(N))
while (($#files)) {
something with $files[1,10]
files[1,10]=()
}
Oder:
autoload -U zargs
xargs -l10 -- *.txt -- something with
zsh
Beachten Sie auch, dass Sie in den Globs einen Bereich verwenden können :
something with *.txt([1,10])