Ищем команду для следующей задачи:
У меня есть три файла, каждый с двумя столбцами, как показано ниже.
Я хотел бы создать file4
с четырьмя столбцами.
Вывод должен напоминать отсортированную версию file1
, file2
и file3
, так что первый столбец отсортирован, второй столбец — второй столбец file1
, третий столбец — второй столбец file2
, а четвертый столбец — второй столбец file3
.
Записи в столбцах со 2 по 3 не должны быть отсортированы, но должны соответствовать паре "ключ-значение" в первом столбце исходных файлов.
Я пробовал пересечение в Linux, но не дал желаемых результатов.
Любая помощь будет оценена. Заранее спасибо!!
$ cat -- file1
A1 B5
A10 B2
A3 B15
A15 B6
A2 B10
A6 B19
$ cat -- file2
A10 C4
A4 C8
A6 C5
A3 C10
A12 C14
A15 C18
$ cat -- file 3
A3 D1
A22 D9
A20 D3
A10 D5
A6 D10
A21 D11
$ cat -- file 4
col1 col2 col3 col4
A1 B5
A2 B10
A3 B15 C10 D1
A4 C8
A6 B19 C5 D10
A10 B2 C4 D5
A12 C14
A15 B6 C18
A20 D3
A21 D11
A22 D9
🤔 А знаете ли вы, что...
Bash позволяет работать с переменными окружения для настройки поведения скриптов.
( echo "col1, col2, col3, col4" &&
awk 'ARGIND==1 { a[$1]=$2; allkeys[$1]=1 } ARGIND==2 { b[$1]=$2; allkeys[$1]=1 } ARGIND==3 { c[$1]=$2; allkeys[$1]=1 }
END{
for (k in allkeys) {
print k", "a[k]", "b[k]", "c[k]
}
}' file1 file2 file3 | sort -V -k1,1 ) | column -t -s ','
declare -A a
while read key value; do a[$key] = "${a[$key]:-}${a[$key]:+, }$value"; done < file1
while read key value; do a[$key] = "${a[$key]:-, }${a[$key]:+, }$value"; done < file2
while read key value; do a[$key] = "${a[$key]:-, , }${a[$key]:+, }$value"; done < file3
(echo "col1, col2, col3, col4" &&
for i in ${!a[@]}; do
echo $i, ${a[$i]}
done | sort -V -k1,1) | column -t -s ','
Пояснение к "${a[$key]:-, , }${a[$key]:+, }$value"
пожалуйста, проверьте Shell-Parameter-Expansion
Использование GNU Awk:
gawk '{ a[$1] = substr($1, 1); b[$1, ARGIND] = $2 }
END {
PROCINFO["sorted_in"] = "@val_num_asc"
for (i in a) {
t = i
for (j = 1; j <= ARGIND; ++j)
t = t OFS b[i, j]
print t
}
}' file{1..3} | column -t
Существует простой инструмент под названием join
, который позволяет выполнять эту операцию:
#!/usr/bin/env bash
cut -d ' ' -f1 file{1,2,3} | sort -k1,1 -u > ftmp
for f in file1 file2 file3; do
mv -- ftmp file4
join -a1 -e "---" -o auto file4 <(sort -k1,1 "$f") > ftmp
done
sort -k1,1V ftmp > file4
cat file4
Это выводит
A1 B5 --- ---
A2 B10 --- ---
A3 B15 C10 D1
A4 --- C8 ---
A6 B19 C5 D10
A10 B2 C4 D5
A12 --- C14 ---
A15 B6 C18 ---
A20 --- --- D3
A21 --- --- D11
A22 --- --- D9
Я использовал ---
для обозначения пустого поля. Если вы хотите красиво напечатать это, вам нужно повторно проанализировать его с помощью awk или чего-либо еще.
Это может сработать для вас (GNU sed и sort):
s=''; for f in file{1,2,3}; do s = "$s\t"; sed -E "s/\s+/$s/" $f; done |
sort -V |
sed -Ee '1i\col1\tcol2\tcol3\tcol4' -e ':a;N;s/^((\S+\t).*\S).*\n\2\t+/\1\t/;ta;P;D'
Замените пробелы на табуляции и вставьте количество табуляции между ключом и значением в зависимости от того, какой файл обрабатывается.
Отсортируйте вывод по ключевому порядку столбцов.
Объедините каждую строку с ее ключом и распечатайте результат.