web-dev-qa-db-ja.com

シェルコマンドを使用してファイルの最初のn行と最後の行を削除するにはどうすればよいですか?

クエリの結果を含むElement_queryというファイルがあります。

SQL> select count (*) from element;

[Output of the query which I want to keep in my file]

SQL> spool off;

シェルコマンドで1行目と最終行を削除したい。

38
pmaipmui

GNU sedを使用:

sed -i '1d;$d' Element_query

仕組み:

  • -iオプションはファイル自体を編集します。必要に応じて、そのオプションを削除し、出力を新しいファイルまたは別のコマンドにリダイレクトすることもできます。
  • 1dは最初の行を削除します(1は最初の行のみを操作し、dは削除します)
  • $dは最後の行を削除します($は最後の行のみを操作し、dは削除します)

さらに進む:

  • 範囲を削除することもできます。たとえば、1,5dは最初の5行を削除します。
  • ステートメントSQL>を使用して、/^SQL> /dで始まるすべての行を削除することもできます。
  • /^$/dで空白行をすべて削除できます
  • 最後に、セミコロン(statement1;statement2;satement3;...)で区切るか、コマンドラインで個別に指定する(-e 'statement1' -e 'statement 2' ...)ことにより、任意のステートメントを組み合わせることができます。
55
user43791

頭;頭

{   head -n[num] >/dev/null
    head -n[num]
}  <infile >outfile

上記を使用すると、最初のheadコマンドを使用して出力の先頭から取り除く最初の行数と、書き込む行数outfileを指定できます。秒で。また、通常、これはsedよりも速く実行されます-特に入力がlargeの場合-2つの呼び出しが必要ですが。ただし、sedは間違いなくすべきの方が望ましいですが、<infilenot正規の場合lseekable file-これは通常notが意図したとおりに機能するためですが、sedはすべての出力変更を1つのスクリプトプロセスで処理できます。

GNU headを使用すると、2番目のコマンドでも-[num]の否定形を使用できます。この場合、次のコマンドは入力から最初と最後の行を削除します。

{   head -n1 >/dev/null
    head -n-1
}  <infile >outfile

または、POSIX sed

たとえば、20行の入力を読んでいて、最初の3行と最後の7行を取り除きたいと思った場合、sedで削除することを決意した場合、テールバッファーを使用してそれを行います。最初に3と7を足して合計ストリップ数を10にしてから、次のようにします。

seq 20 | sed -ne:n -e '3d;N;1,10bn' -eP\;D

これは、入力から最初の3行と最後の7行を取り除く例です。アイデアは、スタックのパターンスペースの入力の末尾から削除したいだけの行をバッファリングできますが、引き込まれたすべての行について、最初の行のみをPrintします。

  • 行では1,10sedPrintsは何もしないので、branchループの行ごとにパターンスペースに入力をスタックします。
  • 3行目では、sedのすべてのスタックがdeletedです。そのため、最初の3行は一度に出力から削除されます。
  • sedが入力の$last行に達してNextをプルしようとすると、EOFがヒットし、処理が完全に停止します。ただし、その時点でパターンスペースには、すべての行14,20が含まれています-Printedはまだありません。
  • 1行おきにsedPrintsはパターンスペースで最初に発生する\newlineまでのみであり、Deletesは、残っているもので新しいサイクルを開始する前に同じです-または次の6行の入力。 7番目の行は、新しいサイクルでNextコマンドを使用してスタックに再度追加されます。

したがって、seqの出力(20の連続番号の付いた行)のうち、sedは次の出力のみを出力します。

4
5
6
7
8
9
10
11
12
13

これは、sedのパフォーマンスがパターンスペースのサイズに直接比例するため、入力の末尾から削除する行の数が多い場合に問題になります。それでも、多くの場合、これは実行可能なソリューションです。POSIXでは、バスティングの前に少なくとも4 KBを処理するsedパターンスペースを指定しています。

8
mikeserv

この解決策を試してください:

tail -n +2 name_of_file | head -n-1

カスタマイズ

tail;の+2を変更して、最初のn行を削除するように簡単に変更できます。
またはhead-1を変更する最後のn行を削除します。

5
Gabrer

awkの範囲の間の行を選択できます(これは、行の数がわかっていることを前提としています)。

awk 'NR>1 && NR < 3' file

またはPerlでは:

Perl -ne 'print if $.>1 && $.<3' file

行数がわからない場合は、grepを使用してその場で計算できます(これは空白行をカウントしないことに注意してください。grep -c '' fileを使用してそれらもカウントします):

awk -vm="$(grep -c . file2.txt)" 'NR>1 && NR<m' file2.txt
4
terdon

複数の行を削除する方法についてはお答えしません。私はこの方法で問題を攻撃します:

grep -v '#SQL>' Element_query >outfile

行を数える代わりに、プロンプトを認識することでSQLコマンドを排除します。その後、このソリューションは、2つよりも多くのコマンドを含むSQLセッションの他の出力ファイルに対して一般化できます。

4
Monty Harder

edは「標準のテキストエディター」であり、GNU sedがないシステムで使用できます。元々はテキストエディターとして設計されていましたが、しかし、スクリプトに適しています。

printf '%s\n' 1d '$d' w q | ed Element_query

1dはファイルの最初の行を削除します$d(シェルが変数と見なさないように引用)は最後の行を削除し、wはファイルを書き込み、qedを終了します。 printfは、ここでedのコマンドをフォーマットするために使用されます-それぞれの後に改行が必要です。もちろん、これを実現する他の方法があります。

4
evilsoup

SQLコマンドを切り捨てることで、はるかに良い結果が得られます。これは、次の2つの方法で実行できます。

  1. あなたが絶対に確信している場合シーケンス「SQL> "は、出力の他の場所では発生しません

    grep -v -F 'SQL> ' < infile > outfile
    
  2. よくわからない場合は

    grep -v '^SQL> .*;$' < infile > outfile
    

2番目のバージョンは、速度は遅くなりますがより正確です。「SQL>」で始まりセミコロンで終わる行は無視されます。セミコロンは、削除したい行を説明しているようです。

ただし、そもそもその余分な出力をファイルに入れない方がよいでしょう。ほとんどのSQLシステムには、これを行う方法がいくつかあります。私はOracleに精通していませんが、多分 この答え が役立つかもしれません。

3
LSerni

ファイルから先頭行と末尾行を削除するには、いくつかの方法があります。

awkは、パターンマッチングと行カウントの両方を処理するため、使用できます。

#you need to know length to skip last line, assume we have 100 lines
awk 'NR>1 && NR<100 {print $0};' < inputfile
#or
awk '/SQL/ {next}; {print $0;};' < inputfile |awk 'NR>1&& NR<10 {print $0};'

grep -vを使用して、不要な行をパターンで除外できます。また、-Eオプションを使用して複数のパターンに一致させることができます。

grep -v -E "SQL>" < inputfile > outputfile

headおよびtailを使用して、特定の行数をトリムできます。

lines=$((`wc -l < inputfile`-2)) #how many lines in file, less 2
head -n-1 < inputfile | head -n$lines > outputfile
#or
tail -n+2 < inputfile | head -n$lines > outputfile

vi/vimを使用して、最初と最後の行を削除できます。

vi inputfile
:1
dd
:$
dd
:w! outputfile
:x

perlスクリプトを使用して、最初の行をスキップし、各行を保存し、次の行を取得したら印刷することができます。

#left as exercise for the reader :-)
3
ChuckCottrill

awkの使用:

< inputfile awk 'NR>1 {print r}; {r=$0}' > outputfile
  • < inputfileinputfileのコンテンツをawkstdinにリダイレクトします
  • > outputfileawkのコンテンツstdoutoutputfileにリダイレクトします
  • NR>1:処理中のレコードの数が1より大きい場合にのみ、次のアクションを実行します
  • {print r}:変数rの内容を出力します
  • {r=$0}:処理中のレコードの内容を変数rに割り当てます

したがって、awkスクリプトの最初の実行では、最初のアクションブロックは実行されませんが、2番目のアクションブロックが実行され、レコードの内容が変数rに割り当てられます。 2回目の実行では、最初のアクションブロックが実行され、変数rの内容が出力されます(前のレコードが出力されます)。これには、処理された各行を印刷する効果がありますが、最初の行と最後の行は印刷されます。

1
kos