Use ex
, the POSIX file editor
ex
is the non-visual form of the vi
file editor. It actually predates vi
. vi
(and Vim) still use ex
commands; any time you type a colon and enter a command, that is an ex
command (though Vim has many custom extensions).
Since ex
opens the whole file for reading, rather than operating in a stream, addressing can work backwards as well as forwards, unlike in Sed or Awk.
For this particular edit, use the following one liner:
printf '%s\n' 'set ignorecase' '$+?searchword?i' 'NEWLINE_1_ADDED' 'NEWLINE_2_ADDED' 'NEWLINE_3_ADDED' . x | ex input.txt
To test the command (print to standard output rather than saving to file), use %p
rather than x
as the final command:
printf '%s\n' 'set ignorecase' '$+?searchword?i' 'NEWLINE_1_ADDED' 'NEWLINE_2_ADDED' 'NEWLINE_3_ADDED' . %p | ex input.txt
To handle multiple files:
for f in *.txt; do
printf '%s\n' 'set ignorecase' '$+?searchword?i' 'NEWLINE_1_ADDED' 'NEWLINE_2_ADDED' 'NEWLINE_3_ADDED' . x | ex "$f"
done
Explanation
Running the printf
command by itself, you can see the commands which are passed to ex
:
set ignorecase
$+?searchword?i
NEWLINE_1_ADDED
NEWLINE_2_ADDED
NEWLINE_3_ADDED
.
x
The set
command is self-explanatory.
$+
refers to the line after the last line, and ?...?
means to search backward from there. (The +
makes it so a file with a matching last line will be handled correctly.) i
means to "insert" text before the line found.
The .
on a line by itself ends the text to be inserted.
x
saves and exits.
Short awk
solution:
awk '/cluster_name/{ cl=NR }/host_name/ && NR-1==cl' hosts.cluster.conf
/cluster_name/{ cl=NR }
- capturing the record number of "cluster_name"
line
/host_name/
- on encountering "host_name"
line
NR-1==cl
- ensuring that the current "host_name"
record number NR
is next after "cluster_name"
record number (presented by cl
)
The output:
"host_name" : "worker02.sys87.com",
"host_name" : "worker03.sys87.com",
"host_name" : "worker05.sys87.com",
In case if host_name
appears as the 1st line, though I doubt about that in real case, use the following version:
awk '/cluster_name/{ cl=NR }/host_name/ && cl && NR-1==cl' hosts.cluster.conf
Best Answer
Just start reading from the bottom and print the last word of the first line containing at least "something":
For example:
If you happen to not have
tac
, just use the same logic when reading the file normally:That is, store the last word whenever there is "something" in a line. Finally, print the stored value.