BASH: итерация двух переменных в цикле for - PullRequest
1 голос
/ 15 июня 2011

У меня есть два файла: numbers.txt (1 \ n 2 \ n 3 \ n 4 \ n 5 \ n) и alpha.txt (a \ n n \ n c \ n d \ n e \ n)

Теперь я хочу перебрать оба файла одновременно, что-то вроде.

   for num in `cat numbers.txt` && alpha in `cat alpha.txt`
   do 
   echo $num "blah" $alpha
   done

Или у меня была другая идея:

   for num in `cat numbers.txt`
   do
     for alpha in `cat alpha.txt`
     do
      echo $num 'and' $alpha
      break
     done
   done

но этот вид кода всегда принимает первое значение $ alpha.

Надеюсь, моя проблема достаточно ясна.

Заранее спасибо.


Вот то, что я на самом деле собирался сделать. (Это просто пример)

У меня есть еще один файл, скажем, template.txt с содержимым.

    variable1= NUMBER
    variable2= ALPHA

Я хотел бы взять выходные данные из двух файлов, то есть numbers.txt и alpha.txt (по одной строке от обоих одновременно), и хочу заменить NUMBER и ALPHA соответствующим содержимым из этих двух файлов.

Итак, вот что я сделал, когда узнал, как перебирать оба файла вместе.

    paste number.txt alpha.txt | while read num alpha
    do 
     cp template.txt  temp.txt
     sed -i "{s/NUMBER/$num/g}" temp.txt
     sed -i "{s/ALPHA/$alpha/g}" temp.txt
     cat temp.txt >> final.txt
    done

Теперь, что у меня есть в final.txt:

    variable1= 1
    variable2= a
    variable1= 2
    variable2= b
    variable1= 3
    variable2= c
    variable1= 4
    variable2= d
    variable1= 5
    variable2= e
    variable1= 6
    variable2= f
    variable1= 7
    variable2= g
    variable1= 8
    variable2= h
    variable1= 9
    variable2= i
    variable1= 10
    variable2= j

Это очень простой и глупый подход. Я хотел знать, есть ли другой способ сделать это ??

Любое предложение будет оценено.

Ответы [ 6 ]

5 голосов
/ 15 июня 2011

Нет, ваш вопрос недостаточно ясен.В частности, неясен способ, которым вы хотите перебирать файлы, но при условии, что вы хотите получить вывод, такой как:

1 blah a
2 blah b
3 blah c
4 blah d
5 blah e

, вы можете использовать утилиту paste, например:1006 *

или даже:

paste -d@ alpha num | sed 's/@/ blah /'
2 голосов
/ 16 июня 2011

Вот альтернативное решение в соответствии с первой предложенной вами моделью:

while read -u 5 a && read -u 6 b
do
   echo $a $b
done 5<numbers.txt 6<alpha.txt

Обозначение 5<numbers.txt указывает оболочке открывать numbers.txt<code> using file descriptor 5. <code>read -u 5 a означает чтение из значения для из файлового дескриптора 5, связанного с numbers.txt .

Преимущество этого подхода перед вставкой состоит в том, что он дает вам точный контроль над тем, как вы объединяете два файла. Например, вы можете прочитать одну строку из первого файла и дважды из второго.

2 голосов
/ 15 июня 2011

Ваш первый цикл невозможен в bash. Ваш второй, без break, будет объединять каждую строку из numbers.txt с каждой строкой из alpha.txt, например:

1 AND a
1 AND n 
1 AND c
...
2 AND a
...
3 AND a
...
4 AND a
...

Ваш break заставляет пропустить все строки из alpha.txt, кроме 1-й (bmk уже объяснил это в своем ответе)

Должна быть возможность организовать правильный цикл с использованием конструкции while loop , но это будет довольно уродливо.

Есть много более простых альтернатив, которые могут быть лучшим выбором, в зависимости от специфики вашей задачи. Например, вы можете попробовать это:

  paste numbers.txt alpha.txt

или, если вы действительно хотите свои "И", тогда что-то вроде этого:

  paste numbers.txt alpha.txt | sed 's/\t/ AND /'

И если ваши числа действительно последовательны (и вы можете жить без 'И'), вы можете просто сделать:

  cat -n alpha.txt 
1 голос
/ 15 июня 2011

Во втором примере внутренний цикл выполняется только один раз из-за break.Он просто выпрыгнет из цикла, то есть вы всегда получите только первый элемент alpha.txt.Поэтому я думаю, что вы должны удалить его:

for num in `cat numbers.txt`
do
  for alpha in `cat alpha.txt`
  do
    echo $num 'and' $alpha
    done
done
0 голосов
/ 12 мая 2013

@ tollboy, я думаю, что вы ищете ответ:

count=1
for item in $(paste number.txt alpha.txt); do
  if [[ "${item}" =~ [a-zA-Z] ]]; then
    echo "variable${count}= ${item}" >> final.txt
  elif [[ "${item}" =~ [0-9] ]]; then
    echo "variable${count}= ${item}" >> final.txt
  fi
  count=$((count+1))
done

Когда вы набираете paste number.txt alpha.txt в своей консоли, вы видите:

1        a
2        b
3        c
4        d
5        e
6        f
7        g
8        h
9        i
10       j

Из Bash'sточка зрения $(paste number.txt alpha.txt) это выглядит так:

1 a 2 b 3 c 4 d 5 e 6 f 7 g 8 h 9 i 10 j

Поэтому для каждого элемента в этом списке выясните, является ли он буквенным или числовым, и распечатайте его в выходной файл.

Наконец, увеличить счетчик.

0 голосов
/ 15 июня 2011

Если многократный цикл не является вашим конкретным требованием, но получение соответствующих строк, то вы можете попробовать следующий код:

for line in `cat numbers.txt`
do
   echo $line "and" $(cat alpha.txt| head -n$line | tail -n1 )
done

head возвращает количество строк, равное значению строкии tail получает последний элемент.

...