Bash:行番号による行のフィルタリング

Bash:行番号による行のフィルタリング

行と列の多い区切りファイル()がある場合data.txt

346 dfd asw  34
565 sd  wdew 34
667 ffg wew  23
473 sa  as   21
533 jhf qwe  54

抽出したい行番号を含む他のファイル(positions.txt

3
5
8

positions.txtこのファイルを使用してその場所を抽出するにはどうすればよいですかdata.txt?以下は私が期待する結果の例です。

667 ffg wew  23
533 jhf qwe  54

答え1

簡単にawk:

awk 'NR==FNR{ pos[$1]; next }FNR in pos' positions.txt data.txt
  • NR==FNR{ ... }- 最初の入力ファイル(例positions.txt:)を処理します。
    • pos[$1]- 累積位置(レコード数)を配列キーにpos設定
    • next- 次のレコードに移動
  • FNR in pos- 2番目の入力ファイルを処理するときdata.txtFNR現在の入力ファイルから読み取られたレコード数を示す)、現在のレコード番号が位置FNR配列にある場合にのみレコードを印刷するpos(キーで検索)

出力例:

667 ffg wew  23
533 jhf qwe  54
...

答え2

まず、ファイルsedからスクリプトを作成します。positions.txt

sed 's/$/p/' positions.txt

これは出力されます

3p
5p
8p

この単純なスクリプトは、指定された行だけを印刷します。

data.txt次にファイルに適用します。使用している場合bash(またはプロセス置換を理解するシェル<( ... )):

sed -n -f <( sed 's/$/p/' positions.txt ) data.txt

指定されたスクリプトによって明示的に印刷された内容を除く-nすべての出力を停止します。sedsed

与えられた例に基づいて、これは次のようになります。

667 ffg wew  23
533 jhf qwe  54

使用しないbash場合

sed 's/$/p/' positions.txt >filter.sed
sed -n -f filter.sed data.txt
rm -f filter.sed

…同じことをします。

答え3

ソートされている場合は、ストレージ全体をpositions.txt使用せずに2つのファイルを同時に渡すことでこれを行うこともできます。以前に一致した行が満たされている場合は、次の行をお読みください。positions.txtpositions.txt

$ awk -vpos=positions.txt 'function get() { getline num < pos } 
     BEGIN { get() } NR==num { print; get() }' data.txt                 
667 ffg wew  23
533 jhf qwe  54

実際、これは両方のファイルが非常に大きい場合にのみ機能します。本物十分な保存。

答え4

単純なforループでこれを行うことができます。

方法 1 は sed と for ループを使用します。

for i in `cat positions.txt`; do sed -n ""$i"p" data.txt ; done

出力

667 ffg wew  23
533 jhf qwe  54

方法 2 は awk と for ループを使用します。

for i in `cat positions.txt`; do awk -v i="$i" 'NR==i {print $0}' data.txt ;done

出力

667 ffg wew  23
533 jhf qwe  54

関連情報