Як прочитати вміст з двох файлів і об'єднати в третій файл в оболонці bash

Як ви читаєте/обробляєте 2 файли в синхронізації один з одним в bash?

У мене є 2 текстові файли, в яких однакова кількість рядків/елементів у них. Один файл є

a
b
c

Інший файл є

1
2
3

How do I loop through these files in sync so that a is associated with 1, b->2, c->3?

Я думав, що я міг би читати в файлах як масив, а потім обробити їх індексом, але мені здається, що мій синтаксис/логіка неправильний.

Таким чином, f1 = $ (cat file1) робить f1 = a b c . Я думав, що виконуючи f1 = ($ (cat file1)) , він перетворить його в масив, але він робить f1 = a , і тому для мене не обробляється масив.

У випадку, коли хтось запитує, що мій код зламаний:

hostnames=($(cat $host_file))  
# trying to read in as an array, which apparently is incorrect
roles=($(cat $role_file))

for i in {0..3}
do
   echo ${hostnames[$i]}   
   # wanted to iterate through each element in the file/array
   # but there is only one object instead of N objects
   echo ${roles[$i]}
done
9
Щоб заповнити масив вмістом файлу, я встановив $ IFS в \ n і скористайтеся командою array = ($ (, а потім використовуйте команду для ((n = 0; n <$ (# array [@]); n ++)); виконайте echo "$ {масив [n]}"; зробили обробляти масив (и).
додано Автор potong, джерело

7 Відповіді

Ви можете використовувати файлові дескриптори :

while read -r var_from_file1 && read -r var_from_file2 <&3; do 
    echo "$var_from_file1 ---> $var_from_file2"
done 

Вихід:

a ---> 1
b ---> 2
c ---> 3
17
додано
Це, безумовно, найкраща відповідь! +1 .
додано Автор gniourf_gniourf, джерело

Використовуйте paste ( виклик ) для об'єднання файлів , а потім обробляти один рядок комбінованого файлу одночасно:

paste file1 file2 |
while read -r first second
do
  echo $first
  echo $second
done
10
додано

Твій шлях:

host_file=host1
role_file=role1

hostnames=(  $(cat $host_file) )  
roles=( $(cat $role_file)  )
(( cnt = ${#hostnames[@]}  -1 ))
echo "cnt is $cnt"
for (( i=0;i<=$cnt;i++))
do
  echo "${hostnames[$i]} ->    ${roles[$i]}"
done
2
додано

Коротким та гнучким рішенням цієї проблеми є core-util pr :

# space separated
$ pr -mts' ' file1 file2
a 1
b 2
c 3

# -> separated
$ pr -mts' -> ' file1 file2
a -> 1
b -> 2
c -> 3

Див. man pr для отримання додаткової інформації.

2
додано

два приклади з :

awk '{print $0, NR}' file1

і - набагато краще :-)

awk 'NR==FNR {a[NR]=$0;next};{print a[FNR], $0}' file1 file2

..вихід завжди:

a 1
b 2
c 3
2
додано

Код для GNU :

  • with file1 in front:

    sed -r 's#(.*)#s/(.*)/\1 \\1/;$!n#' file1|sed -rf - file2
    

    or

  • with file2 in front:

    sed -r 's#(.*)#s/(.*)/\\1 \1/;$!n#' file2|sed -rf - file1
    

Обидва приводять до одного виходу:

a 1
b 2
c 3
d 4
e 5
f 6
g 7
2
додано
@chirlu ви маєте рацію, якщо коса риси Regex повинні бути змінені (трохи) :-)
додано Автор captcha, джерело
Будемо сподіватися, що на вході немає косих слів. :-) Погляньте на пасти file1 file2 , хоча.
додано Автор chirlu, джерело

Чистий баш:

IFS=$'\n'
hostnames=( $( 

або після коментарю gniourf_gniourf

mapfile -t hostnames < hostnames.txt
mapfile -t roles < roles.txt

for idx in ${!hostnames[@]}; do              # loop over array indices
  echo -e "'${hostnames[idx]}' '${roles[idx]}'"
done
0
додано
час (1) не показує суттєвої різниці при використанні 30000 лінійних файлів. Вимикач -t вилучає кінцеві нові рядки. Для мене зміст масиву рівний в обох версіях. Чи я щось не помічаю?
додано Автор Fritz G. Mehner, джерело
Дякую. Слово issue може бути виправлено шляхом встановлення IFS. Вибір картелю можна залишити читачеві.
додано Автор Fritz G. Mehner, джерело
На жаль, поля в ваших масивах не містять рядків у файлі, а слова! Вам краще використовувати mapfile таким чином: mapfile-t hostnames , і це також набагато ефективніше!
додано Автор gniourf_gniourf, джерело
це робиться на моїй системі, яка, ймовірно, старша і повільніше, ніж ваша. Крім того, $ (...) запускає підпрограму, тоді як mapfile не має. Крім того, a = ($ ( створить масив, поля якого є словами файлу, а не його рядками.
додано Автор gniourf_gniourf, джерело