web-dev-qa-db-ja.com

行番号のリストに基づいてファイルから行を読み取り、ユーティリティに出力を書き込む

別のファイルから読み取りたい行のリストを含むファイルがあります。これらの行をユーティリティ(grep)に出力して、行全体を読み取り、そこから情報を取得できるようにします。行のあるファイルは次のようになります。

cat input.txt
2088
2089
2095
2096

どういうわけか私はこれで立ち往生しています。 sedが特定の行番号を引数として取ることができることは知っていますが、これを変数に入れてフィードする方法がわかりません。

5
binswagger
awk 'NR==FNR{linesToPrint[$0];next}
     FNR in linesToPrint' line-numbers.txt file.txt
2

私があなたの問題を正しく理解していれば、このようなことがうまくいくはずです:

for i in $(cat numbers.txt); do cat lines.txt|tail -n +$i|head -n 1; done

ファイル「numbers.txt」内の番号ごとに、他のファイルの対応する行を抽出して出力します。

sedxargsの同じものは次のようになります。

xargs -i sed "{}q;d" lines.txt <numbers.txt
1
michas

michasの解釈 が正しいと仮定すると、ここにawkソリューションがあります。

awk 'FNR==NR{a[i++]=$0} # Process the first file
     FNR!=NR{           # Process the second file
         for (i in a){
             if(FNR==a[i]){
                 print $0
             }
         }
     }' file_with_line_numbers other_file

Perlの場合:

Perl -E '
    while(<>){
        chomp;
        if($file2) { say if exists $lines{$.} }
        else       { $lines{$_}++             }
    }   continue   { if (eof){$.=0; $file2++} }'\
    file_with_line_numbers other_file
1
Joseph R.
sed '/[^0-9]/d;s/.$/&p/' <input.txt |
sed -nf - file

これは、2つのsedが連携して機能することです。 1つ目は、数字以外の1文字を含む行の印刷を拒否し、少なくとも1文字を含む行のみを編集することにより、適切な行のみを編集するように少し試みます。ただし、基本的にその仕事は、行番号のリストを次のように変換することです。

2088p
2089p
2095p
2096p

2番目は標準入力からコマンドスクリプトを読み取り、デフォルトでは行を出力しないため、最初のsedによって編集されたすべての行は、2番目のsedのコマンドのリストになります。これらのコマンドはfileで実行されます。

どうやら同様の手法がすでに推奨されているようですが、プロセスの呼び出し引数と入力の間には根本的な違いがあります。次のような引数リストには明確な制限があります。

some_process $(seq a billion)

そのようなことは必ず失敗しますが、プロセスがそれを処理する方法を知っている限り、その入力は理論的には無制限です。したがって、この場合、sedはファイルを読み取ります-|pipe-入力として、sedスクリプトのように処理します。これは、呼び出し時にコマンドラインで同じ長さの文字列を渡すのとは大きく異なります。

1
mikeserv

sedxargs および printf と組み合わせる:

_sed -n $(xargs printf "%sp;" < input.txt) data
_

_-n_は、明示的に指示しない限り、行を印刷しないようにsed に指示します。 xargs は、標準入力からの行を引数としてコマンドを実行します。 printf は、説明されているように各引数をフォーマットします。上記の$(...)は(サンプルファイルの場合)次のように展開されます。

_2088p;2089p;2095p;2096p;
_

これは、行2088、2089、2095、および2096を印刷するように指示する一連のsedコマンドです。

このようにして、_xargs -i sed "{}q"_またはパイプされたheadtailに対して何度もではなく、各ファイルを1回読み取ります。

0
Michael Homer

別のPerlソリューション:

$ Perl -MList::Util=any -nle '
    BEGIN {
        open $fh, "<", "input.txt";
        @lines = <$fh>;
        close $fh;
    }
    print if any { $_ == $. } @lines;
' file
0
cuonglm