Extraiga el rango de elementos del i-ésimo elemento al j-ésimo elemento, hasta el enésimo elemento de una lista

Extraiga el rango de elementos del i-ésimo elemento al j-ésimo elemento, hasta el enésimo elemento de una lista

En un directorio tengo una cierta cantidad de archivos. Podrían ser 53 archivos txt, pero también podría tener 123 archivos. Los archivos tienen varios nombres aleatorios, pero todos tienen el identificador de archivo..txt

Puedo obtener una lista de todos los archivos con ls y ponerla en una variable.

list_of_txt_files=$(ls *.txt)

Pero me gustaría dividir la lista en varias listas individuales, cada lista con sólo 10 elementos, es decir, una carpeta con 53 archivos txt, debería darme 6 listas. Es decir, 5 listas con 10 nombres de archivos y una sexta lista con 3 nombres de archivos, y mi ejemplo con 123 archivos txt en un directorio debería darme 12 listas con 10 nombres de archivos y una decimotercera lista con solo 3 nombres de archivos. .

Con mi ejemplo con 53 archivos txt: lista no. 1 mantendría el primer archivo hasta el décimo archivo y listaría no. 2 mantendría desde el undécimo archivo hasta el vigésimo, y así sucesivamente. Titulé mi pregunta del iésimo al jésimo elemento de una lista, ya que supongo que otras personas podrían querer dividir la lista de manera diferente. Quizás desde el primer archivo hasta el archivo número 100 en un directorio.

El objetivo final es poder usar estas listas en un bucle for do y usar el comando cat para escribir el contenido de diez archivos por lista en un archivo por conjunto de diez archivos; es decir, en mi ejemplo con 53 archivos en un directorio, esto me daría 6 archivos. Donde los primeros 5 archivos contienen el contenido de los 50 archivos txt originales y el sexto archivo contiene el contenido de los últimos 3 archivos txt restantes.

He considerado usar el comando head o tail, pero no puedo entender cómo especificar rangos para estos dos comandos.

Respuesta1

En un caparazón conmatrices, usalos, usalos a ellos. Decir con 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

Elexpansión de subcadena(segmento de matriz) "${files[@]:i:10}"se expande a una lista de palabras, no a una sola cadena, por lo que puede recorrerla en bucle:

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

Nodo files=$(ls *.txt), lses completamente redundante allí, es el shell el que evalúa el comodín de todos modos. Por lo general, simplemente guarda el patrón comodín en una variable ( pat=*.txt) y lo usa (sin comillas) cuando sea necesario, o si desea expandirlo a los nombres de archivos reales, úselo echo *.txten lugar de ls. Para manejar listas de nombres de archivos, las matrices son mejores, si no está limitado a un shell POSIX simple.


En cuanto a dividir una lista con heady tail, necesitaría hacer algo como | head -20 | tail -10obtener las líneas 11 a 20. O usar sed: | sed -n 11,20p.

Respuesta2

Con cualquier shell tipo Bourne (excepto el shell Bourne que no podía acceder a elementos posicionales $9), puedes hacer:

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

Con GNU xargsy shells con soporte para sustitución de procesos:

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

Con zsh:

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

O:

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

También tenga en cuenta que puede utilizar un rango en zshlos globos:

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

información relacionada