2つのファイルがあります。File1
いくつかの文が含まれており、File2
保持したい行番号が含まれていますFile1
。
たとえば、File1
:
He is a boy.
She is a cook.
Okay.
She went to school.
She is pretty.
File2
:
1
4
出力:
He is a boy.
She went to school.
sed
、またはを使用してgrep
これを行う方法はありますかawk
?行番号を手動で書きたくありません。ここ。
答え1
数値リストを一連のコマンドに変換し、単一の呼び出しで編集スクリプトとして実行できますsed
。sed
sed
sed 's/$/p/' lines.list | sed -n -f /dev/stdin file.txt
ここでは、まずthisのようなコマンドで構成されたスクリプトをsed
作成し、各行の末尾に挿入するだけです。その後、スクリプトは、スクリプトを読み取り、テキストファイルと共に入力として適用するパイプの後の2番目に送信されます。sed
1p
4p
p
sed
-f /dev/stdin
これを行うには、各ファイルを一度だけ読み取る必要があります。
を使用してawk
行番号を連想配列のキーとして読み込み、別のファイルを読み取るときに現在の行番号が以前に配列に入力された行番号の1つであることを確認してください。
awk 'FNR == NR { lines[$0]; next } (FNR in lines)' lines.list file.txt
のawk
特殊変数NR
とFNR
は、それぞれこれまでに読み込んだ総レコード(行)の数と、現在のファイルから読み取った総レコード(行)の数です。NR
等しい場合は、FNR
最初の入力ファイルから読み込み、現在の行をキーとして$0
配列項目を作成し(値が指定されていない)、すぐに次の入力行にジャンプします。
現在行を読み取っていない場合は、現在のファイルの行番号が配列のキーであるかどうかをFNR in lines
テストします。その場合、現在の行が印刷されます。FNR
lines
このユーティリティは、実際に他のツールの強力なサポートなしにgrep
これらのタスクを実行するためのものではありません。コンテンツが指定されたパターンと一致する(または一致しない)テキストファイルから行を抽出します。したがって、パターンは行番号ではなく行と一致する必要があります。
以下は娯楽目的でのみ提供されており、実際にこの問題を解決する方法についてのアドバイスとして受け入れてはいけません。
あなたはできます入れる行番号とgrep
使用法
grep -n '.*' file.txt
これにより、ファイルのすべての行の先頭に行番号が挿入され、その後に行の元の:
内容が挿入されます。
その後、ソリューションと同様に、sed
パターンファイルを変更してこれらの特定の数字の選択と一致させることができます。
sed 's/.*/^&:/' lines.list
^1:
これにより、 などの正規表現が出力され^4:
、それぞれは行の先頭の特定の行番号と一致します。
その後、これらの式を使用できますgrep
(ここでは手続き型置換の助けを借りて)。最後に、次を使用して一時行番号を削除しますcut
。
grep -n '.*' file.txt | grep -f <(sed 's/.*/^&:/' lines.list) | cut -d : -f 2-
...しかし、これはあまりにも人為的であり、合理的な解決策であるとは思えません。
上記の各ソリューションは、常に選択した行をテキストファイルに表示される順序で表示します。ファイルに表示される順序で行を出力するにはsed
(またはawk
以下を参照)を使用できます。
sed 's/$/p/' lines.list | ed -s file.txt
p
繰り返しますが、各行の末尾に単に追加して、行番号ファイルから編集スクリプトを作成します。
スクリプトはコマンド入力としてed
エディタに渡され、エディタはコマンドを順番にテキストファイルに適用します。
テスト:
$ cat lines.list
4
1
$ sed 's/$/p/' lines.list | ed -s file.txt
She went to school.
He is a boy.
sed
以下の対応するプログラムと同様に、ファイル全体をメモリに読み込みますawk
。
awk 'NR == FNR { lines[FNR] = $0; next } { print lines[$0] }' file.txt lines.list
以前のソリューションと比較して入力ファイルが切り替えられましたawk
。これにより、最初にlines
テキストファイルを1行ずつ配列に読み込み、次に行番号を持つファイルを読み込みながらランダムに行を選択できます。
答え2
ファイルが行番号file.txt
であり、含まれているとします。lines.txt
使用xargs
:
# extract digit sequences from lines.txt and make sed arguments
sed 's/[^[:digit:]]*\([[:digit:]]\+\)[^[:digit:]]*/-e \1p /g' lines.txt \
| xargs /bin/sh -c '[ $# -gt 0 ] && sed -n "$@" file.txt' sh
答え3
使用幸せ(以前のPerl_6)
#Sample Input:
~$ cat data.txt
He is a boy.
She is a cook.
Okay.
She went to school.
She is pretty.
インデックスを示す連続例:
~$ raku -e '.put for lines[ 0,3 ];' data.txt
He is a boy.
She went to school.
#Take line-number index inline (subtract 1 to make zero-indexed):
~$ raku -e 'my @index = <1 4>; .put for lines[ @index.map: *-1 ];' data.txt
He is a boy.
She went to school.
インデックスをファイルパスとして使用して、コマンドラインからデータを取得します。
~$ raku -e 'my @ind = "/path/to/index.txt".IO.lines;
.put for lines[ @index.map: *-1 ];' data.txt
He is a boy.
She went to school.
コマンドラインから次の2つのファイルをインポートします(data.txt
その後index.txt
)。
~$ raku -e 'my @data = @*ARGS[0].IO.lines;
my @index = @*ARGS[1].IO.lines;
.put for @data[ @index.map: *-1 ];' data.txt index.txt
He is a boy.
She went to school.
答え4
File2のターゲット行番号が昇順の場合は、この方法を使用できます。
sed -e 's/$/b/;$a d' < File2 |
sed -f - File1
一連の sed コマンドの生成
1b
4b
d
File2に与えられた順序でFile1の行を印刷する一般的なケースでは、次の2つのいずれかを使用します。
awkを使用して、File1の行番号と値を行の内容として使用して連想配列を作成します。ただし、File2に記載されている行と一致しない追加の行のみが保存されます。 Fikle2のターゲット行番号から始まり、数値的にインクリメントされるインデックスでキーが指定され、値フィールドがターゲット行番号である別の配列が保持されます。
awk '
{if (X) c[b[FNR]]=$0; else b[a[NR]=$1]=$1}
END {for (i=1; i in a; i++) print c[a[i]]}
' File2 X=1 File1
Slurp モード -z で GNU sed を使用します。しかし、まずFile2の内容を表示するコマンドを生成します。
sed -e 's:.*:s/^(.*\\n){&}/\\1\\d0/M;P;g:' File2 |
sed -zEn -e h -f - File1 | tr -d '\0'