1

29 個のファイルから行を読み取り、これらの行を処理して if ステートメントに入れたいと考えています。

この例では、基本的に while ループを使用してファイルを読み取り、各ファイルからこれらの行を読み取り、if ステートメントで sed を使用して処理する 3 つのサンプル ファイルと 1 つのシェル スクリプト ファイルを作成しました。この 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

予想される出力は次のとおりです。

<variable id="abc.def">
   <a2>123</a2>
   <b2>123</b2>
   <c2>12344</c2>
</variable>
<variable id="efg.hij">
   <a2>456</a2>
   <b2>45666</b2>
   <c2>45666</c2>
</variable>
<variable id="kml.nop">
   <a2>789</a2>
   <b2>897</b2>
   <c2>123</c2>
</variable>
4

4 に答える 4

3

以下は、任意の数のファイルを比較し、それらの内容が順序どおりである必要はありません (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
于 2013-08-09T14:38:34.123 に答える
3

を使用readして、各行を名前と値に簡単に分割し、事前に作成されたテンプレートを使用しprintfて出力を簡単にすることができます。また、ifステートメントにいくつかの構文エラーがありました。空白が重要です。

シェルは、10 個を超えるファイル記述子を独自に使用するために予約しているため、この方法では 29 個の入力ファイルにうまく対応できません。bash4.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
于 2013-08-09T13:54:50.973 に答える
2

bash以外の別の言語を気にしない場合は、 awkをお勧めします(私が awk に精通しているという理由だけでなく、テキスト処理にも優れているため)。これが私のawkソリューションで、これをtext2xml.awkと呼んでいます:

BEGIN {
    FS="=" # Use the equal sign as field separator
}

# When we encounter a new file, establish a new tag based on the file
# name
#   tag:      tag names,  (a2, b2, c2, ...)
#   tagfound: keep track of which tag has been found
#   tags:     array of tag names, where tags[0] = "a2", ...
#   tagcount: number of tags
FNR == 1 {
    tag = FILENAME
    sub(/\..*$/, "2", tag) # Replace extension with number 2, a.txt ==> a2
    if (!(tag in tagfound)) {
        tags[tagcount++] = tag
    }
    tagfound[tag] = 1
}

# For each line in each file, we parse the id, add that id to a list
# then store the value for later display.
#   id:      abc.def, efg.hij, ...
#   idfound: keep track of which id has been found
#   ids:     List of id, ids[0] = "abc.def", ...
#   values:  two-dimensional array, values[id,tag] stores the right-
#            hand-side of the equal sign
{
    sub(/^ */, "") # Remove leading spaces
    if (!($1 in idfound)) { ids[idcount++] = $1 }
    idfound[$1] = 1
    values[$1,tag] = $2
}

# Loop through the ids and tags, display the XML
END {
    for (i=0; i<idcount; i++) {
        id = ids[i]
        printf "<variable id=\"%s\">\n", id
        for (j=0; j<tagcount; j++) {
            tag = tags[j]
            printf "  <%s>%s</%s>\n", tag, values[id,tag], tag
        }
        printf "</variable>\n"
    }
}

使用するには:

awk -f text2xml.awk a.txt b.txt c.txt  # Try out with 3 files
awk -f text2xml.awk *.txt              # For all .txt files

討論

意味を理解できるように、コードに十分なコメントを入れていただければ幸いです。必要に応じて、さらに質問をしてください。

  • ID の順序は、テキスト ファイル内での表示方法によって異なります。
  • タグ (a2、b2、c2、...) の順序は、コマンド ラインからのファイルの順序によって異なります。
  • awkを知っている人にとっては、idfound配列を反復処理して and を忘れることができidsますidcount。ただし、このアプローチは ID の順序を保証しません。順序が重要だと感じています。tagfoundtagcount、についても同様ですtags
  • このソリューションは 3 つのファイルで機能しますが、29 個以上のファイルで機能するはずです。
  • Mac OS X 10.8 Mountain Lion でこのソリューションをテストしていますが、他のプラットフォームでも動作するはずです。

アップデート

phani の要求に従って、タグから.txtを削除するようにコードを修正します。次の行を置き換えます。

    sub(/\..*$/, "2", tag) # Replace extension with number 2, a.txt ==> a2

と:

    sub(/\.txt$/, "", tag) # Remove the .txt extension
于 2013-08-09T18:31:09.473 に答える