Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
连接和比较来自bash的大量输入文件_Bash_Shell_If Statement_While Loop - Fatal编程技术网

连接和比较来自bash的大量输入文件

连接和比较来自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

我想从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
    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个文件及以上
  • 我正在测试这个