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


31

Element_queryクエリの結果を含む名前のファイルがあります:

SQL> select count (*) from element;

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

SQL> spool off;

シェルコマンドを使用して1行目と最後の行を削除したい。


2
SQL * Plus内でこれを修正するのが最善でしょう。ファイルを生成してから、不要なものを削除しようとするのではなく、SQL * Plusにそのようなものを生成しないように指示できます。1つのアプローチは、docs.oracle.com / cd / A84870_01 / doc / sqlplus.816 / a75664 / ch44.htmの「フラットファイルの作成」セクションで説明されています。別のアプローチはstackoverflow.com/q/2299375/978917で説明されています。
-ruakh

回答:


48

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' ...)で個別に指定することで、任意のステートメントを組み合わせることができます。

3行目を削除する場合... 1dの代わりに3dを使用する必要がありますか?最後から3行目を削除する場合...コマンドはどうなりますか?
pmaipmui

シェルコマンドを使用して最後から3行目を削除するにはどうすればよいですか?
pmaipmui

@Nainita範囲を指定することができます(1,3d最初の3行が削除されます)が、最後には少し難しくなります。必要に応じて、この:sed -i '/^SQL> /d' Element_queryを使用SQL> して、ファイルのどこにあるかに関係なく始まる行を削除することをお勧めします。
user43791

@Nainita- 任意のテールカウントについての私の答えを参照しください- ファイルの終わりに関連してカウント行を削除するための2つのソリューションを提供します。1つはsed1行- ファイルの先頭末尾から任意の行数を削除するために機能しますが、入力が通常のファイルである限り、2つのheadプロセスに単一の入力をグループ化するだけです-通常これを行う最速の方法。
mikeserv

以前sed -i '1d' table-backup.sqlは、SQLテキストファイルの最初の行を削除していました
David Thomas

8

頭; 頭

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

上記を使用すると、最初のheadコマンドで出力の先頭から取り除く最初の行数outfileと、2番目のコマンドで書き込む行数を指定できます。また、通常は、2回の呼び出しを必要とするにもかかわらず、sed特に入力が大きい場合よりも高速にこれを行います。ただし、通常のlseekableファイルではない場合はsed間違いなく優先されるべきです。これは通常、そのような場合に意図したとおりに機能しませんが、単一のスクリプトプロセスですべての出力変更を処理できるためです。<infilesed

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

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

またはPOSIXの場合sed

たとえば、20行の入力を読んでいて、最初の3行と最後の7行を削除したいと考えた場合、w / sedで解決するとしたら、テールバッファを使用します。最初に3と7を足し合わせて合計10のストリップカウントにしてから、次のようにします。

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

これは、入力から最初の3行と最後の7行を削除する例です。アイデアは、スタック上のパターンスペースの入力の末尾から削除したい数の行をバッファーに入れることができるが、P引き込まれたすべての行に対してこれらの最初の行のみをリントすることです。

  • ライン1,10 sed P上では何もリントしません。これは、それらのそれぞれに対して、ランチループでラインごとにパターンスペースに入力を積み重ねているためですb
  • 3行目では、のすべてsedのスタックdが削除されます。したがって、最初の3行は1回で出力から削除されます。
  • ときにsed到達した$プルへの入力と試みの最後の行NEXTをそれがEOFを打つと完全に処理を停止します。しかし、その時点では、パターンスペースにはすべての行が含まれ14,20ていますP。いずれもまだリントされていません。
  • 1行sed Pおきに\n、パターンスペースで最初に発生するewline までしかリントせず、残りの行Dまたは次の6行の入力で新しいサイクルを開始する前にそれを削除します。7番目の行はN、新しいサイクルでextコマンドを使用してスタックに再び追加されます。

そのため、seqの出力(連続した20行の行)のうち、次のものsedのみが出力されます。

4
5
6
7
8
9
10
11
12
13

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


1
GNUはtail、拡張サポートtail -n+<num>「ラインからのスタートという意味の構文<num>
UloPe

4

多数の行を削除する方法には答えません。この方法で問題を攻撃します。

grep -v '#SQL>' Element_query >outfile

行をカウントする代わりに、プロンプトを認識することでSQLコマンドを削除します。このソリューションは、2つ以上のコマンドを使用して、SQLセッションの他の出力ファイルに一般化できます。


私はそれが好きです。私はSQLについてあまり知りませんが、そうでない場合、出力行の先頭にプロンプ​​トが表示される可能性はありませんか?
mikeserv

4

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

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

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


3

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

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 :-)

1
heads については、実際にはパイプは必要ありません。実際、パイプを使用できなければ、パイプをまったく使用しない方が良いでしょう。あなたが行うとhead | head- 2つのプロセスが同時に実行できる一方で、彼らはまた、両方の実質的にすべての重複同じデータを処理しています。代わりに{ head >dump; head >save; } <inオフセットでスキップするだけです-最初は10行を>dump読み取り、2番目は次の 10行を読み取ります>save
mikeserv

3

あなたは、はるかに良いによって提供されると思い切り取る SQLコマンドを。これは2つの方法で実行できます。

  1. シーケンス " "が出力内のどこにも発生しないことが確実な場合、SQL>

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

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

2番目のバージョンはより遅くなりますが、より正確です。 "SQL>"で始まりセミコロンで終わる行を無視します。

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


3

範囲内の行を選択できます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

3

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

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

カスタマイズ

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


最初の行を印刷するため、このソリューションは正しくありません。
xhienne

1
@xhienne申し訳ありませんが、それは間違いでした。「tail」のパラメーターとして2ではなく1を書きました。これで動作します、ありがとう!:)
ガブラー

1

を使用してawk

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

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


最初の行を除外していません。NR == 2で、に保存された入力の最初の行を印刷しrます。
xhienne
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.