使用 Bash 和 process substitution,您可以在一个(相当长的)命令管道中对三个文件执行此操作:
join -e 0 -a 1 -a 2 -t $'\t' -o 0,1.2,2.2 \
<(sed 1d sample001.file | sort) \
<(sed 1d sample002.file | sort) |
join -e 0 -a 1 -a 2 -t $'\t' -o 0,1.2,1.3,2.2 \
- <(sed 1d sample003.file | sort)
请注意,join 要求其输入在连接列上排序,在本例中为第 1 列。 sed 1d 命令在对数据进行排序之前删除标题行。
当缺少值时,-e0 会说 'put 0。 -a1 和 -a2 选项表示“保留文件 1 和文件 2 中的所有行”。 -t $'\t' 选项使用 Bash 的 ANSI C Quoting 为分隔符生成选项卡。如果您省略 -t 选项,它“有效”,但输出列由空格分隔,而不是制表符。 -o 选项指定要打印的列:0 是连接列(每个文件中的第 1 列); 1.2 是文件 1 中的第 2 列,等等。第二个 join 中的文件名 - 表示“读取标准输入”。
样本数据的输出是:
James 0 0 65
Joey 54 23 0
Kyle 87 76 34
Marge 87 0 23
Pedro 0 76 76
Sia 43 0 65
这里有一些处理 10 个示例文件的代码。我也需要生成数据,所以我使用了我的工具包中的一些工具来做到这一点——random、perturb、range(非常类似于标准的seq)和shuffle:
for sample in $(range -f '%03d' 1 10)
do
random -n 9 -T '%{ABCDEFJKMPS}s %[11:90]d %{BG}s' |
sort -u -k1,1 |
join -o 1.2,2.2,2.3 names - |
shuffle |
sed 's/ / /g' |
perturb -f '%2.0f' -p 10 -c 2 > "sample$sample.file"
done
随机数据生成器的一个小问题是它还不允许您从(多字符)名称列表中选择随机条目,因此我使用了首字母列表并将它们映射到带有 @ 的名称987654345@ 文件。这有点奇怪,但您应该已经拥有数据并且不需要生成随机数据。
文件names 包含:
A Alex
B Belle
C Cynthia
D Doreen
E Elizabeth
F Ferdinand
J James
J Joey
K Kyle
M Marge
P Pedro
S Sia
例如,sample001.file 最终包含:
Belle 81 B
Marge 62 B
Ferdinand 37 B
Sia 44 B
Doreen 45 G
Elizabeth 18 G
Joey 16 B
James 19 B
然后加入代码需要在进行任何加入之前生成所有名称的列表,否则您不会看到第一个示例文件中没有出现的名称的正确分数。这不使用任何非标准工具。
tmp=$(mktemp ./tmp.XXXXXX)
trap 'rm -f "$tmp" "$tmp".?; exit 1' 0 1 2 3 13 15
sed 's/[[:space:]].*//' "$@" | sort -u > $tmp.0
join_cmd()
{
join -e 0 -a 1 -a 2 -o "$outcols" "$@" > "$tmp.2"
}
outcols="0,2.2"
# Generate list of all names
join_cmd "$tmp.0" <(sort "$1")
mv "$tmp.2" "$tmp.1"
shift
outcols="0,1.2,2.2"
for sample in "$@"
do
join_cmd "$tmp.1" <(sort "$sample")
sed 's/[[:space:]]\([0-9][0-9]*\)$/,\1/' "$tmp.2" > "$tmp.1"
done
# Don't hard code the output file name — do that on the command line that
# invokes this script (same as you specify the input file names on the command line).
sed 's/,/ /g' "$tmp.1" # > integrate.file
rm -f "$tmp" "$tmp".?
trap 0 1 2 3 13 15
这无需通过将数字映射到逗号分隔的列表来不断扩展连接列的列表。
$ column -t integrate.file
Alex 0 0 78 0 65 21 0 38 64 0
Belle 81 12 15 58 0 27 0 13 0 52
Cynthia 0 58 0 52 12 0 0 77 0 94
Doreen 45 49 0 85 0 0 57 32 81 63
Elizabeth 18 64 19 39 18 94 52 0 0 25
Ferdinand 37 0 0 0 0 64 72 21 0 28
James 19 0 0 77 0 48 78 59 39 23
Joey 16 0 0 79 0 48 78 70 39 19
Kyle 0 80 0 65 54 26 0 88 0 0
Marge 62 37 13 0 0 81 0 0 24 69
Pedro 0 0 40 0 47 74 79 0 0 0
Sia 44 0 27 0 55 0 43 0 32 0
$
您可以在输出的第 2 列中看到 sample000.file 的内容。并且可以看到names中的所有名字都出现在了输出中,并且每个样本文件都有一个编号。