1行に1つずつ、並べ替えられた一連の番号を含む3つのファイルがあります。
file1
1
2
3
file2
1
3
4
file
1
5
これらの3つのファイルを次のように並べて「整列」させたい:
file1 file2 file3
1 1 1
2
3 3
4
5
sdiff
で試しましたが、2つのファイルでしか機能しません
各ファイルを処理して、文字を含む行を印刷できます。 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を使用した一般的な解決策:requires 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
、および悪趣味のソリューション:
#! /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つの一時ファイルといくつかのシャッフルを使用して実行することもできます(ただし、それによって悪趣味が増えるだけです)。