Perbandingan berdampingan lebih dari dua file yang berisi nilai numerik


8

Saya memiliki tiga file yang berisi urutan angka, satu per baris:

file1

1
2
3

file2

1
3
4

file3

1
5

Saya ingin "menyelaraskan" ketiga file ini berdampingan seperti berikut:

file1  file2  file3
1      1      1
2      
3      3
       4
              5

Saya sudah mencoba sdifftetapi hanya berfungsi dengan 2 file


Apakah kamu menguji diff3?
Costas

@ Costas diff3tidak memiliki format output itu.
Kusalananda

@Costas Ya, saya sudah menguji dengan diff3dan sebagai @Kusalananda dinyatakan dengan benar, itu tidak menghasilkan output. Juga, saya mencari solusi generik (untuk file n, n> 2)
cheseaux

Jika Anda membandingkan baris demi baris mengapa 5pada baris kelima hasilnya malah ketiga?
Costas

Saya tidak membandingkan baris demi baris
cheseaux

Jawaban:


6

Anda dapat memproses setiap file dan mencetak garis dengan beberapa karakter misalnya Xuntuk setiap nomor yang hilang dalam urutan 1- max (di mana max adalah angka terakhir dalam file itu), pastehasilnya kemudian mengganti karakter itu dengan spasi:

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 ' '

Jika nilai tertentu hilang dari semua file Anda akan mendapatkan baris kosong di output Anda (sebenarnya mereka tidak kosong, mereka hanya berisi kosong).
Untuk menghapusnya ganti tr X ' ' dengan sed '/[[:digit:]]/!d;s/X/ /g' Juga, jika Anda membutuhkan header Anda selalu dapat menjalankan sesuatu seperti ini terlebih dahulu:

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

Tapi aku kesulitan menemukan apa arti ;1bagian di bagian akhir. Saya menggunakan {print $0}sebaliknya, IMHO sedikit lebih samar. Ngomong-ngomong, terima kasih lagi
cheseaux

5

Solusi umum dengan awk: membutuhkan 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   

Mengambil pendekatan yang berbeda dan lebih sederhana untuk ini berdasarkan komentar Don:

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                   

Oke. Jawaban diperbarui
glenn jackman

3

Sebuah solusi dengan bash, join, paste, dan rasa tidak enak:

#! /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

Kecuali yang terakhir sort -n, semua ini berfungsi dengan item teks apa pun alih-alih angka, asalkan item tidak mengandung tab (tetapi TABdapat diubah ke pemisah lainnya). Juga, itu bisa dilakukan hanya dengan 3 file sementara dan beberapa pengocokan (tapi itu hanya akan menambah rasa tidak enak).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.