script - Recorriendo pares de valores en bash
script linux ejemplos (5)
Estoy de acuerdo con la respuesta propuesta actualmente por fedorqui en el contexto de la pregunta que se hace actualmente. Lo siguiente se proporciona solo para proporcionar algunas respuestas más generales.
Un enfoque más general (para bash 4.0 o más reciente) es almacenar sus pares en una matriz asociativa:
declare -A pairs=( [4_1]=4_2 [5_1]=5_2 [6_1]=6_2 [7_1]=7_2 [8_1]=8_2 )
for i in "${!pairs[@]}"; do
j=${pairs[$i]}
paste "$i.txt" "$j.txt" >"${i}.${j}.txt"
done
Otro (compatible con versiones anteriores de bash) es usar más de una matriz convencional:
is=( 4_1 5_1 6_1 7_1 8_1 )
js=( 4_2 5_2 6_2 7_2 8_2 )
for idx in "${!is[@]}"; do
i=${is[$idx]}
j=${js[$idx]}
paste "$i.txt" "$j.txt" >"$i.$j.txt"
done
Tengo 10 archivos de texto y quiero
paste
cada archivo con su par, de modo que tengo un total de 5 archivos.
Intenté lo siguiente:
for i in 4_1 5_1 6_1 7_1 8_1
do
for j in 4_2 5_2 6_2 7_2 8_2
do
paste ${i}.txt ${j}.txt > ${i}.${j}.txt
done
done
Sin embargo, este código combina todas las combinaciones posibles en lugar de solo combinar los pares coincidentes.
Entonces, me gustaría que el archivo
4_1.txt
se
4_2.txt
con
4_2.txt
,
5_1.txt
con
5_2.txt
, etc.
Hay un patrón común en el que tiene pares de archivos, donde un nombre del par puede derivarse fácilmente del otro. Si el archivo del que conoce el nombre es X y el otro archivo es Y, tiene los siguientes casos de uso comunes.
- Para renombrar, Y es X con una extensión eliminada y / o un sello de fecha agregado.
- Para la transcodificación, Y es X con una extensión diferente y quizás un directorio diferente.
- Para muchas tareas de análisis de datos, X e Y comparten algunas partes del nombre del archivo, pero tienen diferentes parámetros o extensiones.
Todos estos se prestan al mismo esqueleto de código aproximado.
for x in path/to/base*.ext; do
dir=${x%/*} # Trim trailing file name, keep dir
base=${x##*/} # Trim any leading directory
# In this case, $y has a different subdirectory and a different extension
y=${dir%/to}/from/${base%.ext}.newext
# Maybe check if y exists? Or doesn''t exist?
if [ -e "$y" ]; then
echo "$0: $y already exists -- skipping" >&2
continue
fi
mv or ffmpeg or awk or whatever "$x" and "$y"
done
La clave aquí es la observación de que
y
puede derivarse de
x
con algunas sustituciones de variables simples.
Entonces, recorre los valores
x
y calcula el valor
y
correspondiente dentro del ciclo.
Aquí, hemos utilizado los operadores incorporados
${variable#prefix}
y
${variable%suffix}
del shell para devolver el valor de la variable con cualquier
prefix
inicial o
suffix
final, respectivamente, recortados.
(También hay
##
y
%%
para que coincida con la coincidencia más larga posible, en lugar de la más corta posible. La expresión después de
#
o
%
es un patrón de globo de caparazón regular). Por lo general, esto debería ser todo lo que necesita, aunque con frecuencia ve
sed
o guiones
awk
incluso para este trabajo trivial (donde realmente debería intentar evitar un proceso externo), así como, por supuesto, para transformaciones más exigentes.
Si necesita recorrer los archivos
x
dispersos en diferentes directorios, tal vez el ciclo debería comenzar con algo como
find dir1 dir2 etc/and/so/forth -type f -name ''x-files*.ext'' -print |
while IFS='''' read -r x; do
:
Un problema comúnmente visto en preguntas similares son las respuestas que no pueden citar
$x
y
$y
correctamente.
En general, cualquier variable que contenga un nombre de archivo siempre debe estar entre comillas dobles.
Donde X e Y no están relacionados, una solución común es recorrer un documento aquí que contiene la asignación:
while read -r x y; do
: stuff with "$x" and "$y"
done <<''____HERE''
first_x_value first_y_value
another_x corresponding_y
random surprise
____HERE
Puede usar una matriz asociativa:
animals=(dog cat mouse)
declare -A size=(
[dog]=big
[cat]=medium
[mouse]=small
)
declare -A sound=(
[dog]=barks
[cat]=purrs
[mouse]=cheeps
)
for animal in "${animals[@]}"; do
echo "$animal is ${size[$animal]} and it ${sound[$animal]}"
done
Esto le permite atravesar pares, triples, etc. Créditos: la idea original está tomada de la respuesta de @ CharlesDuffy.
Si desea usar una variable y realizar una acción con ella, solo necesita usar un bucle:
for file in 4 5 6 7 8
do
paste "${file}_1" "${file}_2"
done
Esto lo hara
paste 4_1 4_2
paste 5_1 5_2
...
lo anterior no funcionó para mí, pero lo siguiente sí lee valores en pares de una lista ordenada
(pueden ser más que pares agregando ''líneas de lectura'' adicionales :-)
while read x; do
read y
echo $x $y
done << ''___HERE''
X1
Y1
X2
Y2
X3
Y3
___HERE
produce
X1 Y1
X2 Y2
X3 Y3