tac
ファイルの先頭と末尾から空白行を削除する方法 ( を使用) を探していたところ、次の方法を見つけました。
awk 'NF {p=1} p'
これはどのように/なぜ機能するのでしょうか?
私が理解しているのは、フィールドがある場合(行が空白行でない場合)NF
のみです。true
答え1
これにより、先頭の空白行が削除されます。しかし最後からではないファイルの。[注意: この回答は質問を編集する言及したtac
]
動作は次のように行われます。
NF
現在の行にあるフィールドの数です。ゼロの場合、その行は空か空白つまり、最大で空白文字が含まれます (フィールド区切り文字がデフォルト値のままであると仮定すると、連続する任意の数の空白文字が区切り文字として扱われます)。{ ... }
ルール ブロック ( )の外側の (およびルール ブロックに関連付けられていない) 条件が と評価された場合、現在の行が印刷されますtrue
。フラグはp
最初は初期化されておらず、 と評価されるfalse
ため、事前に何も印刷されません。- 空白でない行が見つかると(
NF
はゼロ以外で と評価されますtrue
)、ルール ブロック{p=1}
に入り、フラグp
が に設定されます1
。その後、p
ルール ブロックの外側の は と評価されtrue
、後続の行(現在の最初の空白でない行を含む)が印刷されます。
知らせフラグはp
リセットされないため、最初の非空白行の後に続く空白行はフィルタリングされずに印刷されます。末尾の空白行も削除したい場合は、2 段階のアプローチが必要になります。
awk 'FNR==NR{if (NF) {if (!first) first=FNR; last=FNR} next}
FNR>=first && FNR<=last' input.txt input.txt
これにより、ファイルは 2 回処理されます (したがって、オペランドとして 2 回指定されます)
- 最初のパスでは、
FNR
ファイルごとの行カウンタ がNR
グローバル行カウンタ に等しく、最初と最後の非空白行を識別します。 - 2 回目のパス (
FNR
は より小さくなりますNR
) では、識別された最初の非空白行と最後の非空白行の間 (およびそれらの行を含む) の行のみを印刷します。
知らせ
に記載されているように、ステファン・シャゼラスの回答2 パス アプローチは通常のファイルでのみ機能します。入力が異なる性質の場合は、解決策としてそこで提案されている方法を参照してください。
答え2
このテクニックを使用して、ファイルの先頭と末尾の両方から空白行を削除します。
awk 'NF {p=1} p' file | # remove blank lines at the file head
tac | # reverse the lines
awk 'NF {p=1} p' | # remove blanks from the "new head"
tac | # re-reverse the file
sponge file # from the `moreutils` package, to overwrite the file
答え3
コードが何をするのか、そしてなぜ入力の先頭の空白行だけを削除するのかは、すでに説明されています。@AdminBee の回答たとえば、ここでは完全性を保つために、ファイルを 2 回処理せずに先頭と末尾の空白行の両方を削除する別の方法を提案します (これは通常のファイルに対してのみ機能し、任意の入力に対しては機能しません)。
awk '
NF {print saved $0; saved = ""; started = 1; next}
started {saved = saved $0 ORS}' < file
空白行の印刷を、その後に現れる次の非空白行まで遅らせます (その前に少なくとも 1 行の非空白行がすでに現れている場合)。
答え4
残しておきたい空白行のスペースやタブを消しても構わない場合は、次のようにすると先頭と末尾の空白行が削除されます。
awk 'NF{for(;c;--c)print "";print;x=1;next} x{++c}'
非空白行の間にある空白行の数をカウントし、各非空白行の前にその数の空行を出力します。