0

私は、shell(linux)の次の問題に対する完全な解決策ではなく、アイデアを探しています。最善の解決策は何ですか?(awk、while-loop、sed ....)

同じ行構造のファイルが2つありますkey-value-value。これら2つのファイルをマージしたいと思います。値が存在しない場合、スクリプトは新しい行を挿入します。存在する場合、スクリプトは値を更新します(値を合計することによって)。

Example:
File 1:

john-15-40
doo-10-91
mary-14-19
foo-11-0

File 2:

foo-110-10
john-22-11
ghost-1000-1000

Result:
foo-121-10
john-37-51
ghost-1000-1000
doo-10-91
mary-14-19

これどうやってするの?

4

5 に答える 5

4

awkでシンプル

awk '
  BEGIN {FS = OFS = "-"}
  {v1[$1] += $2; v2[$1] += $3}
  END {for (key in v1) {print key, v1[key], v2[key]}}
' F1 F2
于 2012-04-28T11:29:02.313 に答える
1

PHPで要求しなかったのは知っていますが、役立つかもしれません。必要に応じて、おそらく別の言語にも似たようなものがあります。

<?PHP

$file_handle = fopen("file1", "r");

while (!feof($file_handle) ) {
$line_of_text = fgets($file_handle);
list($name,$value1,$value2) = explode('-', $line_of_text);
$file1[$name]=array($value1,$value2);
}
fclose($file_handle);
// repeate for file2
//then use the 2 arrays, $file1[] and $file2[] to rewrite the file as 'file3' or whatever. 
//Checking for duplicates and doing the math.
?>
于 2012-04-28T10:40:22.213 に答える
1

これはBash4でネイティブに実行できます。

#!/bin/bash
declare -A vals_one vals_two
while IFS=- read key val1 val2; do
  if [[ ${vals_one["$key"]} ]] ; then
    vals_one["$key"]=$(( ${vals_one["$key"]} + val1 ))
    vals_two["$key"]=$(( ${vals_two["$key"]} + val2 ))
  else
    vals_one["$key"]=$val1
    vals_two["$key"]=$val2
  fi
done < <(cat input1.txt input2.txt)
for key in "${!vals_one[@]}"; do
  printf '%s-%s-%s\n' "$key" "${vals_one[$key]}" "${vals_two[$key]}"
done

このアプローチはメモリ効率がやや悪いことに注意してください。よりメモリ効率の高いアプローチでは、ファイルをマージする前に並べ替えます(GNU並べ替えは、並べ替える内容がメモリに収まらない場合に一時ファイルを生成できるため、これを作成する合理的なスクリプトよりも優れています)、したがって、一度に2行をメモリに保存するだけで済みます。

#!/bin/bash

function merge_inputs {
    IFS=- read key val1 val2
    while IFS=- read new_key new_val1 new_val2; do
      if [[ $key = "$new_key" ]] ; then
        val1=$(( val1 + new_val1 ))
        val2=$(( val2 + new_val2 ))
      else
        printf '%s-%s-%s\n' "$key" "$val1" "$val2"
        key=$new_key
        val1=$new_val1
        val2=$new_val2
      fi
    done
    printf '%s-%s-%s\n' "$key" "$val1" "$val2"
}
sort input1.txt input2.txt | merge_inputs

また、この後者の形式は連想配列を必要とせず、古いバージョンのbash(または、いくつかの適応により、他のシェル)で機能します。

于 2012-04-28T11:55:41.813 に答える
1

連想配列を備えた言語が必要です。あなたの仕事はどんなスクリプト言語にとっても非常に簡単ですが、perlとawkはテキストファイルを1行ずつ処理するのに特に適しています。

擬似コード:

read line from file1, file2
split line to key and values
if there are no key in hash
     add key and values
else
     add values and print key/values
于 2012-04-28T10:26:43.790 に答える
1

私はグレンのshort fat解決策が好きです。そして、tall thin解決策があります。

2つのファイルがある場合:1.txt2.txt

sort {1,2}.txt |
awk -F- -vOFS=- '
NR==1{
    x=$1
}
x==$1{
    y+=$2
    z+=$3
    next
}
{
    print x,y,z;
    x=$1
    y=$2
    z=$3
}
END{
    print
}'
于 2012-04-28T11:58:40.550 に答える