Сравнение бок о бок с более чем двумя файлами, содержащими числовые значения

У меня есть три файла, содержащие отсортированную последовательность чисел, по одной в строке:

file1

  • Печать строки после n-го появления совпадения
  • awk одна строка
  • Найти больше дубликатов
  • Как разместить предложения по отдельным строкам в Linux
  • Поиск определенного членства в группе пользователей с точным соответствием
  • Удалите повторяющиеся строки, сохраняя порядок строк
  • 1 2 3 

    file2

     1 3 4 

    file3

     1 5 

    Я хочу «выровнять» эти три файла бок о бок, как показано ниже:

     file1 file2 file3 1 1 1 2 3 3 4 5 

    Я пробовал с sdiff но он работает только с 2 файлами

  • Удаление строк между 2 строками в Solaris
  • Прокрутите список через awk
  • Необходимо отфильтровать данные на основе двух столбцов, имеющих много отношений, используя awk
  • Вычитание одной текстовой строки из другой, оставляя уникальные символы, возможно, используя awk
  • Перечисленная частота различных строк в отдельной колонке
  • Извлеките значение из вывода команды и используйте значение в качестве параметра для следующей команды
  • 3 Solutions collect form web for “Сравнение бок о бок с более чем двумя файлами, содержащими числовые значения”

    Вы можете обрабатывать каждый файл и печатать строку с некоторым символом, например X для каждого недостающего числа в последовательности 1- max (где max – это последнее число в этом файле), paste результаты, затем заменить этот символ пробелом:

     paste \ <(awk 'BEGIN{n=1};{while (n<$1) {print "X";n++}};{n=$1+1};1' file1) \ <(awk 'BEGIN{n=1};{while (n<$1) {print "X";n++}};{n=$1+1};1' file2) \ <(awk 'BEGIN{n=1};{while (n<$1) {print "X";n++}};{n=$1+1};1' file3) \ | tr X ' ' 

    Если какое-то значение отсутствует во всех файлах, вы получите пустые строки в своем выходе (на самом деле они не пустые, они содержат только пробелы).
    Чтобы удалить их, замените tr X ' ' на sed '/[[:digit:]]/!d;s/X/ /g' Также, если вам нужен заголовок, вы всегда можете запустить что-то вроде этого:

      printf '\t%s' file1 file2 file3 | cut -c2- 

    Общее решение с awk: требует GNU awk

     gawk -v level=0 ' FNR==1 {level++; head[level]=FILENAME} !seen[$1]++ { n++; idx[$1] = n } { out[idx[$1]][level] = $1 } END { for (j=1; j<=level; j++) { printf "%s\t", head[j] } print "" for (i=1; i<=n; i++) { for (j=1; j<=level; j++) { printf "%s\t", out[i][j] } print "" } } ' file{1,2,3,4} 
     file1 file2 file3 file4 1 1 1 2 2 3 3 4 4 5 6 

    Взял другой и более простой подход к этому, основываясь на комментарии Дона:

     gawk ' FNR==1 { printf "%s\t", FILENAME } { seen[$1][FILENAME] = $1 } END { print "" PROCINFO["sorted_in"]="@ind_num_asc" for (i in seen) { for (j=1; j<=ARGC; j++) { printf "%s\t", seen[i][ARGV[j]] } print "" } } ' file{1,2,3,4} 
     file1 file2 file3 file4 1 1 2 3 3 4 4 5 5 6 7 

    Решение с bash , join , paste и bad taste:

     #! /usr/bin/env bash if [ $# -lt 3 ]; then exit 1; fi files=( '' "$@" ) declare -a temps for ((i=0; i<=$#; i++)); do [ $i -eq 0 -o -f "${files[$i]}" ] || exit 1 temps[$i]=$( mktemp -t "${0##*/}"_$$_XXXXXXXX ) || exit 1 done trap 'rm -f "${temps[@]}"' EXIT HUP INT QUIT TERM cat "$@" | sort -u >"${temps[0]}" TAB=$( printf '\t' ) for ((i=1; i<=$#; i++)); do join -j1 -a1 -t"$TAB" "${temps[0]}" <(paste "${files[$i]}" "${files[$i]}") | \ sed "/^[^$TAB]\$/ s/\$/$TAB/" >"${temps[$i]}" done printf '%s' ${files[1]} for ((i=2; i<=$#; i++)); do printf '\t%s' ${files[$i]} let j=i-1 let k=i-2 join -j1 -t"$TAB" "${temps[$j]}" "${temps[$i]}" >"${temps[$k]}" cat "${temps[$k]}" >"${temps[$i]}" done printf '\n' cut -d "$TAB" -f 2- <"${temps[$#]}" | sort -n 

    За исключением последнего sort -n , все это работает с любыми текстовыми элементами, а не с числами, если элементы не содержат вкладок (но TAB можно изменить на любой другой разделитель). Кроме того, это можно сделать только с тремя временными файлами и некоторыми перетасовками вокруг (но это только увеличит плохой вкус).

    Linux и Unix - лучшая ОС в мире.