Eu tenho 10 arquivos de texto e quero paste
cada arquivo com seu par, de modo que eu tenha 5 arquivos no total.
Eu tentei o seguinte:
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
No entanto, esse código combina todas as combinações possíveis em vez de apenas combinar os pares correspondentes.
Então eu gostaria que o arquivo 4_1.txt
fosse emparelhado com 4_2.txt
, 5_1.txt
com 5_2.txt
, etc.
Se você quiser usar uma variável e executar e ação com ela, você só precisa usar um loop:
for file in 4 5 6 7 8 do paste "${file}_1" "${file}_2" done
Isso fará
paste 4_1 4_2 paste 5_1 5_2 ...
Concordo com a resposta atualmente proposta por fedorqui no contexto da questão atualmente formulada. O abaixo é dado apenas para fornecer algumas respostas mais gerais.
Uma abordagem mais geral (para o bash 4.0 ou mais recente) é armazenar seus pares em uma matriz associativa:
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
Outro (compatível com versões mais antigas do bash) é usar mais de um array 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
Você pode usar um dictionary / hashMap:
animals=(dog cat mouse) declare -A sound=( [dog]=barks [cat]=purrs [mouse]=cheeps ) declare -A size=( [dog]=big [cat]=medium [mouse]=small ) for animal in "${animals[@]}"; do echo "$animal ${sound[$animal]} and it is ${size[$animal]}" done
Desta forma, você pode trabalhar com tuplas (pares), “triplos”, etc – qualquer tipo de dictionary / dados hashMap.
Créditos: A idéia principal é tirada da grande resposta do @ CharlesDuffy.
Existe um padrão comum onde você tem pares de arquivos, onde um nome do par pode ser facilmente derivado do outro. Se o arquivo que você sabe o nome de é X e o outro arquivo é Y, você tem os seguintes casos de uso comuns.
Todos estes se prestam ao mesmo esqueleto de código bruto.
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
A chave aqui é a observação de que y
pode ser derivado de x
com algumas substituições de variables simples. Então você faz um loop sobre os valores x
e descobre o valor y
correspondente dentro do loop.
Aqui, usamos os operadores ${variable#prefix}
${variable%suffix}
${variable#prefix}
e ${variable%suffix}
do shell para retornar o valor da variável com qualquer prefix
ou final, respectivamente. (Há também ##
e %%
para coincidir com a correspondência mais longa, em vez da mais curta possível. A expressão depois de #
ou %
é um padrão regular de shell glob.) Geralmente, eles devem ser tudo o que você precisa, embora scripts awk
até mesmo para este trabalho trivial (onde você realmente deveria tentar evitar um processo externo), assim como, é claro, para transformações mais exigentes.
Se você precisar fazer um loop de x
arquivos espalhados por diretórios diferentes, talvez o loop deva começar com algo como
find dir1 dir2 etc/and/so/forth -type f -name 'x-files*.ext' -print | while IFS='' read -rx; do :
Um problema comumente visto em questões semelhantes são as respostas que não citam corretamente $x
$y
. Geralmente, qualquer variável que contenha um nome de arquivo deve estar sempre entre aspas duplas.
Onde X e Y não estão relacionados, uma solução comum é fazer um loop sobre um documento aqui contendo o mapeamento:
while read -rxy; do : stuff with "$x" and "$y" done <<'____HERE' first_x_value first_y_value another_x corresponding_y random surprise ____HERE