bashスクリプトにパラメータとして渡された特定の行番号のフィールドを抽出する方法は?

bashスクリプトにパラメータとして渡された特定の行番号のフィールドを抽出する方法は?

data.txt次のファイルがあります。

 1           aFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
 2           bFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
 3           cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
 4           dFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
 5           eFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
 6           fFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
 7           gFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
 8           hFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
 9           iFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
10           jFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234
11           kFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf        IT524234

最初のフィールドは行番号です。

いくつかの行番号引数を使用してスクリプトを呼び出すことができ、.txtがその行番号の最初と2番目のフィールドを印刷できるようにシェルスクリプトを作成しようとしていますdata.txt。たとえば、次のようget.sh 1 3 5に印刷する必要があります。

1           aFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
3           cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
5           eFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf

awkは最初と2番目のフィールドを印刷するためにのみ使用できると思いますが、シェルスクリプトに渡されたパラメータに基づいて特定の行のみをフィルタリングすることに閉じ込められています。よろしくお願いします。

答え1

awkでは、行番号を配列として収集し、ファイルを一度読み込み、配列に記載されている行を印刷できます。

#!/bin/sh
awk -v lines="$*" 'BEGIN { split(lines, a, "[, ]"); 
                           for (i in a) b[a[i]] = 1;}
                   NR in b {print $1, $2}' < data.txt

スペースとコンマに沿って変数を配列に分割しsplit()、次のようにループから配列を作成します。linesaforbこの配列には、興味のある行が含まれています。次に、NR in b現在の行番号と一致するキーが存在することを確認します。

各行は、入力に何回存在するかにかかわらず、一度だけ印刷され、行は引数で指定された順序ではなく入力番号の順序で印刷されます。

$ bash get.sh 7 3 3
3 cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
7 gFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf

get.sh 7,3,3また有効)

答え2

次の行をテキストファイルに入れ、名前をget.shとして指定します。その後、実行可能にします。

#!/bin/sh
## this is GNU sed
sed -En "
  $(printf '%sbp\n' "$@" "d;")
  :p;s/\S+/&\n/2;P
" data.txt

次に、次のようにスクリプトを呼び出します。

chmod +x ./get.sh
./get.sh 1 3 5

答え3

#!/bin/bash

perl -le '
for (@ARGV) {
  # separate command line args into filename(s) and line-number(s)
  # line-numbers can be space and/or comma separated.
  if (-e $_) { push @files, $_ } else { push @lines, split /,/};
};

@ARGV = @files;
$re = join("|",@lines);

while(<>) {
  print join("\t",(split)[0..1]) if ($. =~ m/^($re)$/);
  close(ARGV) if eof;
}' "$@"

これは、ファイル名ではなくパラメータに基づいて正規表現を作成し、後で各ファイルの行番号を一致させるために使用されます。一致する場合は、入力行をスペースに分割し、最初の2つのフィールドをタブで区切って印刷します。

close(ARGV)これまでに見たすべての入力の行番号ではなく、現在のファイルの行番号に興味があるので必要です。 Perlはファイルハンドルが閉じられたときにのみ変数をリセット$.$NRまたは)しますが、ファイルハンドルは通常ループで閉じられませ$INPUT_LINE_NUMBERん。while(<>)これはリセットできるようにファイルハンドルを明示的に閉じます$.。望むよりperldoc -f eof

$ ./get.sh 1 3,5 data.txt 
1       aFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
3       cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
5       eFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf

もちろん、このスクリプトはPerlの「1行」を囲む無意味なbashラッパーではなく、Perlスクリプトでなければなりません。しかし、人々は1行のコードが「正しい」と思うようですが、#!/bin/bashまたは#!/bin/sh以外のものをインタプリタとして使用するスクリプトは少し間違っています。

#!/usr/bin/perl -l

for (@ARGV) {
  # separate command line args into filename(s) and line-number(s)
  # line-numbers can be space and/or comma separated.
  if (-e $_) { push @files, $_ } else { push @lines, split /,/ };
};

@ARGV = @files;
$re = join('|',@lines);

while(<>) {
  print join("\t",(split)[0..1]) if ($. =~ m/^($re)$/);
  close(ARGV) if eof;
};
$ ./get.pl 1 3,5 data.txt  
1       aFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
3       cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
5       eFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf

これは実際に正確にPerlインタプリタだけをフォークするシェルインタプリタをフォークするのに最小限の時間とメモリを無駄にしないことも同様です。

さらに重要なことは、次の問題を回避することです。シェルリファレンスシェルが含まれていないからです。返品、構文強調スクリプトはシェルスクリプトで一重引用符で囲まれた文字列ではないため、エディタではうまく機能します。そして行番号警告/エラーメッセージは、単一行内の相対行番号ではなくスクリプトファイルの絶対行番号を参照するため、スクリプトをデバッグするときは正確です。

答え4

#! /bin/bash
# get.sh
IFS=$'\n'
args=(`sort -nu <<<$*`)
unset IFS

awk -v lines="${args[*]}" 'BEGIN{split(lines, ar, " ");}{ for (i in ar) { if (NR == ar[i]) print $1,$2} }' data.txt

まずargs、ソートされた一意の値を含む配列を作成します。この目的のために、私たちはオプション科-nを使います。-uより詳しくは

次に変数からsplit配列を作成します。要素がレコード番号(NR)と等しい場合、ループは目的の出力を印刷します。arlinesar

関連情報