我有两个 400,000 行的大文件。我想递归地比较第二个文件的第 1 列与第一个文件的第 1 列。如果它们匹配,我想打印整行。这是一个排序的文件。
file 1:
name values
aaa 10
aab acc
aac 30
aac abc
file2:
aaa
aac
aac
aad
由于该文件包含 400,000 行,因此需要时间来处理。
我目前的解决方案是这样的
#!/bin/ksh
while read line
do
var=`echo $line `
grep "$var" file1 >> /dev/null
if [ $? -eq 0 ]
then
grep "$var" file1 >> present
else
echo " $line missing " > missing
fi
done < "file2"
由于我在这里使用grep
,该值可能出现在 file1 中除预期的 column1 之外的某个位置,我不希望发生这种情况。
我预期的解决方案:
- 仅将第二个文件与第一个文件的第 1 列进行比较(即使我们这样做也需要很长时间)。
- 使用
perl
带有文件指针的脚本比较文件的两列。如果字符串匹配则打印它。否则,如果第一个文件的列 1 大于第二个文件的列,则增加文件 2 并进行比较。如果是反之亦然,则增加文件 1 的列 1 并进行比较。
答案1
join file1 file2
默认情况下,它将为每个文件使用第 1 列,并忽略其中任何一个文件中缺少的行,这就是您想要的。另外,文件需要排序,情况已经如此。
答案2
如果数量独特的中的元素file2
不太大,那么可行的解决方案可能是使用 处理两个文件的经典方法awk
,首先创建 的第 1 列中的唯一元素的数组file2
,然后测试 的 第 1 列file1
是否为数组中的成员资格,即
awk 'FNR==NR {a[$1]++}; FNR!=NR && a[$1]' file2 file1
使用关联数组的等效方法bash 4+
可能类似于
#!/bin/bash
declare -A a
while read col1 _ ; do
((a[$col1]++))
done < file2
while IFS= read -r line; do
# compare only with 1st column of second file
read -r col1 _ <<< "$line"
[[ -n "${a[$col1]}" ]] && printf "$line\n"
done < file1
答案3
这是您正在寻找的东西吗?我习惯cut
将列表拆分为数组,每个数组包含一列。这假设列由制表符分隔。您可以通过指定选项来更改分隔符剪切的使用-d
。在下划线处分割:cut -d '_'
.
#!/bin/bash
FILE1='somefile'
FILE2='someotherfile'
# File 1, column 1
f1c1=($(cut -f1 -s $FILE1))
# File 1, column 2
#f1c2=($(cut -f2 -s $FILE1))
# File 2, column 1
f2c1=($(cut -f1 -s $FILE2))
# File 2, column 2
#f2c2=($(cut -f2 -s $FILE2))
# Looping through all items in file 1 column 1
for x in "${f1c1[@]}"
do
# For each item in f1c1, check all items in f2c1 for a match
for y in "${f2c1[@]}"
do
if [[ $x == $y ]]
then
# The items matched!
echo $x
# Breaking out of the loop (no need to check for more than one
# match, right?)
break
fi
done
done