한 줄에 하나씩 정렬된 숫자 시퀀스가 포함된 세 개의 파일이 있습니다.
파일 1
1
2
3
파일 2
1
3
4
파일 3
1
5
다음과 같이 이 세 파일을 나란히 "정렬"하고 싶습니다.
file1 file2 file3
1 1 1
2
3 3
4
5
이것을 시도했지만 sdiff
2개의 파일에서만 작동합니다.
답변1
X
각 파일을 처리하고 시퀀스 1-의 누락된 각 숫자 와 같은 특정 문자가 있는 줄을 인쇄할 수 있습니다.최고(어디최고파일의 마지막 숫자), 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-
답변2
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
Tang의 의견을 바탕으로 좀 더 다르고 간단한 접근 방식이 채택되었습니다.
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
답변3
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개의 임시 파일과 약간의 혼란만으로 작업을 완료할 수 있습니다(그러나 이는 좋지 않은 맛을 더할 뿐입니다).