3

そのため、さまざまなスクリプト間で情報を保存する手段として、途中で中間テキスト ファイルを生成する一連のスクリプトがあります。基本的に、スクリプトは、ユーザーが削除を承認したデータ内の行を検出します。ソース ファイルから削除される行番号は、ファイルに格納されます。

たとえば、次のようなソース データ ファイルがあるとします。

    a1,b1,c1,d1
    a2,b2,c2,d2
    a3,b3,c3,d3
    a4,b4,c4,d4
    a5,b5,c5,d5
    a6,b6,c6,d6
    a7,b7,c7,d7

中間ファイルには次のようなものが含まれます。

    1 3 4 5 6

スクリプトを実行すると、出力データ ファイルは次のようになります。

    a2,b2,c2,d2
    a7,b7,c7,d7

これはすべて正常に機能し、このコードで修正するものは何もありません。問題は、実際のデータ ファイルを扱っているときに、文字通り数千の数値が削除のために中間ファイルに保存されている場合があることです。これは、膨大な時間がかかるため、ループを使用できないことを意味し、現在の使用方法sederror: too many arguments. 行番号の多くは連続しているので、ここで私の質問に行きます:

一連のスペースで区切られた数字が連続しているかどうかを検出する bash または awk の方法はありますか?

私はそれを超えてすべてを整理することができます.1つ/一連のステップでこれを行う方法に困惑しています. 私の計画は、連続した値を検出できれば、中間ファイルを次のように変更することです。

    1 3 4 5 6

に:

    1 3-6

そして、より管理しやすい方法で、値の各範囲で実行されるコードを記述できるようになります。

リスト内の何万もの数値を扱っているため、可能であれば、各値をループして、前の値よりも 1 ステップ上かどうかを個別に確認することは避けたいと思います。

これが bash/awk で不可能な場合、このタスクを実行してスクリプトに渡される引数の総数を減らし、引数が多すぎるためにエラーが発生する可能性を大幅に減らす別の方法はありますか?

4

4 に答える 4

4

What about this?

BEGIN {
    getline < "intermediate.txt"
    split($0, skippedlines, " ")
    skipindex = 1
}
{
    if (skippedlines[skipindex] == NR)
        ++skipindex;
    else
        print
}
于 2013-05-25T01:59:15.907 に答える
3

catjoin、およびを使用しcutます。

ファイルinfileおよびids :

a1,b1,c1,d1         1
a2,b2,c2,d2         3
a3,b3,c3,d3         4
a4,b4,c4,d4         5
a5,b5,c5,d5         6
a6,b6,c6,d6
a7,b7,c7,d7

選択した行の削除:

$ join -v 2 ids <(cat -n infile) | cut -f 2 -d ' '
a2,b2,c2,d2
a7,b7,c7,d7

どうしたの:

  • 最初に、初期ファイルは各行に id を受け取りますcat -n infile
  • 次に、結果のファイルは、最初の列で ID を保持するファイルと結合されます。
  • 2 番目のファイルの一致しない行のみが出力されます -- join -v 2;
  • ID を持つ最初の列は削除されます。
  • そして、それはきちんとしたシェルのワンライナーです (:

ID を持つファイルが一意の行として記述されている場合でも、次のように ID を持つファイルに翻訳を追加するだけで、上記のワンライナーを利用できます。

$ join -v 2 <(tr ' ' '\n' ids) <(cat -n infile) | cut -f 2 -d ' '
于 2013-05-25T02:29:36.533 に答える
2

@jmihaliczaの答えは、 awk をうまく使用して、ソースファイルから中間ファイルの行と一致する行を選択するという問題全体を解決します。完全を期すために、次の awk プログラムは、可能な場合は個々の行番号のリストを範囲に減らします。これは元の質問に答えると思います。

    { for (j = 1; j <= NF; j++) {
        lin[i++] = $j;
        }
    }

END {
    start = lin[0];
    j = 1;
    while (j <= i) {
        end = start
        while (lin[j] == (lin[j-1]+1)) {
            end = lin[j++];
            }
        if ((end+0) > (start+0)) {
                printf "%d-%d ",start,end
            } else {
                printf "%d ",start
            }
        start = lin[j++];
        }
    }

私が呼び出したこのスクリプトと、次のようmerge.awkなファイルがあるとします。testlin.txt

1 3 4 5 6 9 10 11 13 15

... できるよ:

$ awk -f merge.awk <testlin.txt
1 3-6 9-11 13 15
于 2013-05-25T02:28:00.780 に答える