数値を含む3つ以上のファイルを並べて比較


8

行ごとに1つずつ、並べ替えられた一連の数値を含む3つのファイルがあります。

file1

1
2
3

file2

1
3
4

file3

1
5

これらの3つのファイルを次のように並べて「整列」したいと思います。

file1  file2  file3
1      1      1
2      
3      3
       4
              5

私は試しましたsdiffが、2つのファイルでしか機能しません


テストしdiff3ますか?
Costas

@Costasにdiff3はその出力形式はありません。
クサラナンダ

@Costasはい、私はテストしましたがdiff3、@ Kusalanandaが正しく述べているように、その出力は生成されません。また、私は一般的な解決策を探しています(nファイル、n> 2)
cheseaux

行ごとに比較すると5、結果の3行目ではなく5行目にあるのはなぜですか?
Costas

私は行
ごとに

回答:


6

たとえば、各ファイルを処理して1文字の行を出力できます。たとえば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' Alsoに置き換えます。ヘッダーが必要な場合は、常に次のように実行できます。

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

;1しかし、最後の部分の意味を理解するのに苦労しました。私が使用している{print $0}代わりに、ビット少ない不可解な私見を。とにかく、ありがとう
cheseaux

5

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   

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                   

とった。回答が更新されました
Glennn Jackman

3

ソリューションbashjoinpaste、、悪い味:

#! /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、他の区切り文字に変更できます)、すべてのテキストアイテムが数値ではなく機能します。また、一時ファイルを3つだけ使用して、いくつかの要素をシャッフルすることで実行することもできます(ただし、これにより悪趣味が増すだけです)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.