连接和比较来自bash的大量输入文件
我想从29个文件中读取行并处理这些行,然后将它们放入if语句中 在本例中,我创建了3个示例文件和一个shell脚本文件,基本上使用while循环读取文件,并使用sed和if语句从每个文件和进程中读取这些行,该if语句用于检查所有文件中的第一个变量(例如abc.def),并将其值复制到文件中 例如:连接和比较来自bash的大量输入文件,bash,shell,if-statement,while-loop,Bash,Shell,If Statement,While Loop,我想从29个文件中读取行并处理这些行,然后将它们放入if语句中 在本例中,我创建了3个示例文件和一个shell脚本文件,基本上使用while循环读取文件,并使用sed和if语句从每个文件和进程中读取这些行,该if语句用于检查所有文件中的第一个变量(例如abc.def),并将其值复制到文件中 例如: a.txt abc.def=123 efg.hij=45666 kml.nop=789 qrs.tuv=901 wxy.zabc=234 b.txt a
a.txt
abc.def=123
efg.hij=45666
kml.nop=789
qrs.tuv=901
wxy.zabc=234
b.txt
abc.def=123
efg.hij=45666
kml.nop=897
klm.nop=123
qrs.tuv=901
wxy.zabc=234
c.txt
abc.def=12344
efg.hij=456
kml.nop=123
klm.nop=789
wxy.zabc=234
sprict.sh
#!/bash/bin
count=1
while IFS= read -r lineA && IFS= read -r lineB <&3 && IFS= read -r lineC <&4; do
#splitting the line into two,example from line abc.def=123 slit varaibles as "abc.def" and "123"
A1=`echo "$lineA" | sed -e 's/\=\(.*\)//' `
A2=`echo "$lineA" | sed -e 's/^[^=]*=//' `
B1=`echo "$lineB" | sed -e 's/\=\(.*\)//' `
B2=`echo "$lineB" | sed -e 's/^[^=]*=//' `
C1=`echo "$lineC" | sed -e 's/\=\(.*\)//' `
C2=`echo "$lineC" | sed -e 's/^[^=]*=//' `
if [ [ "$A1" = "$B1" && "$A1" = "$C1"]];then
echo -e "<variable id=\"$A1\">\t
<a2>"$A2"</a2>\t
<b2>"$B2"</b2>\t
<c2>"$C2"</c2>\t
</variable>\n" >> common.txt
fi
done <a.txt 3<b.txt 4<c.txt
a.txt
abc.def=123
efg.hij=45666
kml.nop=789
qrs.tuv=901
wxy.zabc=234
b、 文本
abc.def=123
efg.hij=45666
kml.nop=897
荷兰皇家航空公司nop=123
qrs.tuv=901
wxy.zabc=234
c、 文本
abc.def=12344
efg.hij=456
kml.nop=123
荷兰皇家航空公司nop=789
wxy.zabc=234
sprict.sh
#!/猛击/宾语
计数=1
而IFS=read-r lineA&&IFS=read-r lineB>common.txt
fi
完成你就快到了。您在if块中错放了空格。应该是这样的:
if [[ "$A1" = "$B1" && "$A1" = "$C1" ]];then
请注意,开口括号之间没有空格,而闭合括号之前有空格
你的测试文件中也有一些打字错误。在a.txt
中,您应该更改
klm.nop=789
abca.def=12344
到
在c.txt
中,您应该更改
klm.nop=789
abca.def=12344
到
你就快到了。您在if块中错放了空格。应该是这样的:
if [[ "$A1" = "$B1" && "$A1" = "$C1" ]];then
请注意,开口括号之间没有空格,而闭合括号之前有空格
你的测试文件中也有一些打字错误。在a.txt
中,您应该更改
klm.nop=789
abca.def=12344
到
在c.txt
中,您应该更改
klm.nop=789
abca.def=12344
到
您可以使用read
简化将每行拆分为名称和值的过程,并使用带有printf
的预构建模板简化输出。另外,在if
语句中有一些语法错误:空格很重要
shell保留大于10的文件描述符供自己使用,因此您的方法无法很好地扩展29个输入文件。在bash
4.1及更高版本中,您可以让bash
分配文件描述符
#!/bash/bin
# Redirect from each input file, using bash-assigned file descriptors
exec {afile}<a.txt
exec {bfile}<b.txt
exec {cfile}<c.txt
template='<variable="%s">\n\t<a2>%s</a2>\n\t<b2>%s</b2>\n\t<c2>%s</c2>\n</variable>\n'
while IFS="=" read -r -u "$afile" A1 A2 &&
IFS="=" read -r -u "$bfile" B1 B2 &&
IFS="=" read -r -u "$cfile" C1 C2; do
if [[ "$A1" = "$B1" && "$A1" = "$C1" ]]; then
printf "$template" "$A1" "$A2" "$B2" "$C2"
fi
done
#/猛击/宾语
#使用bash指定的文件描述符从每个输入文件重定向
exec{afile}您可以使用read
简化将每行拆分为名称和值的过程,并使用带有printf
的预构建模板简化输出。另外,在if
语句中有一些语法错误:空格很重要
shell保留大于10的文件描述符供自己使用,因此您的方法无法很好地扩展29个输入文件。在bash
4.1及更高版本中,您可以让bash
分配文件描述符
#!/bash/bin
# Redirect from each input file, using bash-assigned file descriptors
exec {afile}<a.txt
exec {bfile}<b.txt
exec {cfile}<c.txt
template='<variable="%s">\n\t<a2>%s</a2>\n\t<b2>%s</b2>\n\t<c2>%s</c2>\n</variable>\n'
while IFS="=" read -r -u "$afile" A1 A2 &&
IFS="=" read -r -u "$bfile" B1 B2 &&
IFS="=" read -r -u "$cfile" C1 C2; do
if [[ "$A1" = "$B1" && "$A1" = "$C1" ]]; then
printf "$template" "$A1" "$A2" "$B2" "$C2"
fi
done
#/猛击/宾语
#使用bash指定的文件描述符从每个输入文件重定向
下面的exec{afile}比较任意数量的文件,并且不要求它们的内容按顺序排列(正如chepner给出的解决方案那样)。它还使用XMLStarlet生成XML格式的输出,从而保证格式良好
这意味着需要在您的系统上安装XMLStarlet;它通常可打包用于主要操作系统的现代版本
#!/bin/bash
join_files() {
local first
if (( $# == 1 )); then
sort <"$1"
elif (( $# == 2 )); then
join -t= <(sort <"$1") <(sort <"$2")
elif (( $# > 2 )); then
first=$1; shift
join -t= <(sort <"$first") <(join_files "$@")
fi
}
main() {
declare -a items
{
printf '%s\n' '(root'
while IFS='=' read -r -a items; do
set -- "${items[@]}"
name=$1; shift
printf '%s\n' '(variable' "Aid $name"
item_num=1
for item; do
printf '%s\n' "(a$item_num" "-$item" ")a$item_num"
(( item_num++ ))
done
printf '%s\n' ')variable'
done < <(join_files "$@")
printf '%s\n' ')root'
} | xmlstarlet depyx | xmlstarlet fo
}
main a.txt b.txt c.txt
#/bin/bash
join_文件(){
本地优先
如果($#==1));那么
sort下面的代码比较任意数量的文件,并且不要求它们的内容按顺序排列(正如chepner给出的解决方案)。它还使用XMLStarlet生成XML格式的输出,保证格式良好
这确实意味着需要在您的系统上安装XMLStarlet;它通常可打包用于主要操作系统的现代版本
#!/bin/bash
join_files() {
local first
if (( $# == 1 )); then
sort <"$1"
elif (( $# == 2 )); then
join -t= <(sort <"$1") <(sort <"$2")
elif (( $# > 2 )); then
first=$1; shift
join -t= <(sort <"$first") <(join_files "$@")
fi
}
main() {
declare -a items
{
printf '%s\n' '(root'
while IFS='=' read -r -a items; do
set -- "${items[@]}"
name=$1; shift
printf '%s\n' '(variable' "Aid $name"
item_num=1
for item; do
printf '%s\n' "(a$item_num" "-$item" ")a$item_num"
(( item_num++ ))
done
printf '%s\n' ')variable'
done < <(join_files "$@")
printf '%s\n' ')root'
} | xmlstarlet depyx | xmlstarlet fo
}
main a.txt b.txt c.txt
!/bin/bash
join_文件(){
本地优先
如果($#==1));那么
排序如果您不介意使用bash以外的其他语言,我可以建议您使用awk(因为我熟悉它,也因为它是一种很好的文本处理方式)。以下是我的awk解决方案,我称之为text2xml.awk:
讨论
我希望我在代码中添加了足够的注释,以便对您有意义。如果需要,请随时提出更多问题
- ID的顺序取决于它们在文本文件中的显示方式
- 标记(a2、b2、c2等)的顺序取决于命令行中文件的顺序
- 对于那些了解awk的人来说,我们可以迭代通过
idfound
数组,忘记ids
和idcount
。然而,这种方法并不能保证ID的顺序;我感觉顺序很重要。对于tagfound
、tagcount
和标记也一样
- 此解决方案适用于3个文件,它应适用于29个文件及以上
- 我正在Mac OS X 10.8 Mountain Lion上测试此解决方案,但它应该可以与其他平台一起使用
使现代化
根据phani的请求,我修复代码,将.txt从标记中剥离。替换以下行:
sub(/\..*$/, "2", tag) # Replace extension with number 2, a.txt ==> a2
与:
如果您不介意使用bash以外的其他语言,我可以建议您使用awk(因为我熟悉它,也因为它是一种很好的文本处理方式)。以下是我的awk解决方案,我称之为text2xml.awk:
讨论
我希望我在代码中添加了足够的注释,以便对您有意义。如果需要,请随时提出更多问题
- ID的顺序取决于它们在文本文件中的显示方式
- 标记(a2、b2、c2等)的顺序取决于命令行中文件的顺序
- 对于那些了解awk的人来说,我们可以迭代通过
idfound
数组,忘记ids
和idcount
。然而,这种方法并不能保证ID的顺序;我感觉顺序很重要。对于tagfound
、tagcount
和标记也一样
- 此解决方案适用于3个文件,它应适用于29个文件及以上
- 我正在测试这个