Извлечь диапазон элементов от i-го элемента до j-го элемента, вплоть до n-го элемента из списка

Извлечь диапазон элементов от i-го элемента до j-го элемента, вплоть до n-го элемента из списка

В каталоге у меня есть определенное количество файлов. Это могут быть 53 txt-файла, но у меня может быть и 123 файла. Файлы имеют различные случайные имена, но все они имеют дескриптор файла.txt

Я могу получить список всех файлов с помощью ls и поместить его в переменную.

list_of_txt_files=$(ls *.txt)

Но я хотел бы разбить список на несколько отдельных списков, каждый из которых будет содержать всего 10 элементов, то есть папка с 53 txt-файлами должна дать мне 6 списков. То есть 5 списков с 10 именами файлов и 6-й список с 3 именами файлов, а мой пример со 123 txt-файлами в каталоге должен дать мне 12 списков с 10 именами файлов и 13-й список всего с 3 именами файлов.

В моем примере с 53 txt-файлами: список № 1 будет содержать файлы с первого по десятый, а список № 2 будет содержать файлы с одиннадцатого по двадцатый и т. д. Я озаглавил свой вопрос с ith по jth элемент в списке, так как предполагаю, что другие люди захотят разбить список по-другому. Возможно, с первого по сотый файл в каталоге.

Конечная цель — иметь возможность использовать эти списки в цикле for do и использовать команду cat для записи содержимого десяти файлов на список в один файл на набор из десяти файлов — т. е. в моем примере с 53 файлами в каталоге это даст мне 6 файлов. Где первые 5 файлов содержат содержимое 50 исходных txt-файлов, а 6-й файл содержит содержимое последних оставшихся 3 txt-файлов.

Я рассматривал возможность использования команды head или tail, но не могу понять, как указать диапазоны для этих двух команд.

решение1

На ракушке смассивы, используйте их. Скажите с помощью 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

Theрасширение подстроки(срез массива) "${files[@]:i:10}"расширяется до списка слов, а не одной строки, поэтому вы можете выполнить по нему цикл:

for f in "${files[@]:i:10}" ; do
    somecmd "$f"
done

Неdo files=$(ls *.txt), то lsздесь совершенно излишне, в любом случае подстановочный знак вычисляет оболочка. Обычно вы просто сохраняете шаблон подстановочного знака в переменную ( pat=*.txt) и используете его (без кавычек) там, где это необходимо, или, если вы хотите расширить его до фактических имен файлов, используйте echo *.txtвместо ls. Для обработки списков имен файлов массивы просто лучше, если вы не ограничены простой оболочкой POSIX.


Что касается разделения списка с помощью headи tail, вам нужно будет сделать что-то вроде того | head -20 | tail -10, чтобы получить строки с 11 по 20. Или использовать sed: | sed -n 11,20p.

решение2

С любой оболочкой типа Bourne (но с оболочкой Bourne, которая не может получить доступ к позиционным элементам через $9), вы можете сделать следующее:

set -- *.txt
while [ "$#" -gt 0 ]; do
  something with "$1" ${2+"$2"} ${3+"$3"}... ${10+"${10}"}
  [ "$#" -gt 10 ] || break
  shift 10
done

С GNU xargsи оболочками с поддержкой подстановки процессов:

xargs -n10 -r0a <(printf '%s\0' *.txt) something with

С zsh:

files=(*.txt(N))
while (($#files)) {
  something with $files[1,10]
  files[1,10]=()
}

Или:

autoload -U zargs
xargs -l10 -- *.txt -- something with

Также обратите внимание, что вы можете использовать диапазон в zshglob:

something with *.txt([1,10])

Связанный контент