This will remove blank lines from the beginning, but not from the end of a file. [Notice: this answer was witten before the edit to the question that mentioned tac
]
It works as follows:
NF
is the number of fields found on the current line. If it is zero, that means the line is either empty or blank, i.e. contains at most whitespace (assuming the field separator is left at its default value, where any number of consecutive whitspace is considered as separator).
- The current line is printed if any condition outside of (and not associated with) rule blocks (
{ ... }
) evaluates to true
. The flag p
is initially uninitialized and will evaluate to false
, so a priori nothing will be printed.
- Once a non-blank line is found (
NF
is non-zero and evaluates to true
) the rule block {p=1}
is entered and the flag p
set to 1
. After that, the p
outside the rule block evaluates to true
, and any subsequent lines (including the current, first non-blank one) is printed.
Notice that since the flag p
is never reset, any blank lines coming after the first non-blank line will be printed without filtering. If you want to remove blank lines from the end, too, a two-pass approach will be necessary:
awk 'FNR==NR{if (NF) {if (!first) first=FNR; last=FNR} next}
FNR>=first && FNR<=last' input.txt input.txt
This will process the file twice (hence it is specified twice as operand)
- In the first pass, where
FNR
, the per-file line counter is equal to NR
, the global line counter, we identify the first and last non-blank line.
- In the second pass (
FNR
is now smaller than NR
), we only print lines between (and including) the so identified first and last non-blank lines.
Notice
As stated in the answer by Stéphane Chazelas, the two-pass approach only works with regular files. If your input is of a different nature, see the method proposed there for a solution.
awk 'p=!p'
- try to figure out what it does and why. orawk '(FNR%2)'