我有4个文件。我需要检查所有文件是否具有相同的行数。
如果行数不同,我需要检测并输出,例如:
#file1 - 10 lines, file2 - 9 lines, file3 - 10 lines, file4 - 10 lines
Line are miss matched
Number of lines 10 = 9 = 10 = 10
如果它们相等,我想逐行合并文件,如下所示:
文件:
#file1
10
12
11
#file2
Arun
kamal
babu
#file3
300
200
400
#file4
spot1
spot4
spot5
输出:
Set1
10
Arun
300
spot1
Set2
12
kamal
200
spot4
Set3
11
babu
400
spot5
我的代码:
#
id_name=`cat file2`
echo $id_name
id_list=`cat file1`
echo $id_list
#
id_count=`cat file3`
echo $id_count
id_spot=`cat spot_list`
echo $id_spot
SS=`cat id_list | wc -l`
DS=`cat id_name | wc -l`
SF=`cat id_count | wc -l`
DF=`cat id_spot | wc -l`
if [ $SS == $DS == $SF == $DF ] then
echo " Line are matched"
echo " Total line $SS"
for i j in $id_list $id_name
do
for a b in $id_count $id_spot
do
k = 1
echo " Set$k"
$i
$j
$a
$b
done
done
else
echo " Line are Miss matched"
echo " Total line $SS = $DS = $SF = $DF"
fi
答案1
用一个非常简单的方法:
#!/usr/bin/env bash
SS=$(wc -l < file1)
DS=$(wc -l < file2)
SF=$(wc -l < file3)
DF=$(wc -l < file4)
if [[ $SS -eq $DS && $DS -eq $SF && $SF -eq $DF ]]; then
echo "Lines are matched"
echo "Total number of lines: $SS"
num=1
while (( num <= SS )); do
echo "Set$num"
tail -n +$num file1 | head -n 1
tail -n +$num file2 | head -n 1
tail -n +$num file3 | head -n 1
tail -n +$num file4 | head -n 1
((num++))
echo
done
else
echo "Line are miss matched"
echo "Number of lines $SS = $DS = $SF = $DF"
fi
它的效率不是很高,因为它调用了tail
4*number_of_lines 次,但它很简单。
另一种方法是将循环替换while
为awk
:
awk '{
printf("\nSet%s\n", NR)
print;
if( getline < "file2" )
print
if( getline < "file3" )
print
if ( getline < "file4" )
print
}' file1
要逐行连接文件,该paste
命令非常有用。您可以使用它代替循环while
:
paste -d$'\n' file1 file2 file3 file4
或者可能不太明显:
{ cat -n file1 ; cat -n file2 ; cat -n file3; cat -n file4; } | sort -n | cut -f2-
这将输出行,但不带格式(无 Set1、Set2、换行符等),因此您必须随后使用 对其进行格式化awk
,例如:
awk '{
if ((NR-1)%4 == 0)
printf("\nSet%s\n", (NR+3)/4)
print
}' < <(paste -d$'\n' file1 file2 file3 file4)
最后一些注意事项:
- 不要使用大写变量,因为它们可能与环境和内部 shell 变量冲突
- 当您可以重定向输入时,请勿使用
echo "$var" | cmd
或:或cat file | cmd
cmd <<< "$var"
cmd < file
for
循环中只能有一个变量名。for i in ...
有效,反之则for i j in ...
无效- 最好使用
[[ ]]
而不是[ ]
用于测试,请参阅此回答 - 有一个很多的方法来做到这一点
- 您可以选择使用哪种方法,但要注意效率差异:
time
在 10000 行文件上测试的结果:
#first approach
real 0m45.387s
user 0m5.904s
sys 0m3.836s
#second approach - significantly faster
real 0m0.086s
user 0m0.024s
sys 0m0.040s
#third approach - very close to second approach
real 0m0.074s
user 0m0.016s
sys 0m0.036s
答案2
您可以弄清楚如何检查每个文件的行数(提示wc
:)
要获得集合的输出:
paste File{1,2,3,4} | awk -F'\t' -v OFS='\n' '{$1=$1; print "Set"NR, $0, ""}'
$1=$1
用于将输入字段分隔符转换为输出字段分隔符。