Looping sobre pares de valores no bash

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.

  • Para renomear, Y é X com uma extensão removida e / ou um carimbo de data é adicionado.
  • Para transcodificação, Y é X com uma extensão diferente e talvez um diretório diferente.
  • Para muitas tarefas de análise de dados, X e Y compartilham algumas partes do nome do arquivo, mas possuem parâmetros ou extensões diferentes.

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 
Intereting Posts