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

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

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

list_of_txt_files=$(ls *.txt)

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

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

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

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

0
02.06.2017, 13:08
2 ответа

В оболочке с массивами используйте их. Произнесите с помощью 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

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

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

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


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

1
28.01.2020, 02:33

С любой оболочкой, подобной 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

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

something with *.txt([1,10])
1
28.01.2020, 02:33

Теги

Похожие вопросы