Table of Contents
Using awk
Command
Use the awk
command to get the last word of each line from a file in Bash.
1 2 3 4 5 6 7 |
It is line1 It is line2 It is line3 It is line4 It is line5 |
1 2 3 |
awk '{print $NF}' input.txt |
1 2 3 4 5 6 7 |
line1 line2 line3 line4 line5 |
We use the awk command, a powerful text-processing tool allowing you to process and manipulate structured data. The awk
command operated each line individually and performed action based on the predefined patterns and associated actions.
In the above example, the '{print $NF}'
was the pattern-action pair telling the awk
what to do for each line received as input. Here, the pattern was empty, meaning it matched all lines. The print $NF
was the action to print the value of the last field ($NF
) for every line.
In Bash, the $NF
is an awk
variable representing the last field of the specified input line. Note that the awk
automatically split each input line into fields based on the given field separator, and the $NF
held the last field’s value.
Field Separator means a delimiter; by default, it is a whitespace character.
The input.txt
was the input file from which the awk
command read data; you can also replace the input.txt
with the path of your file.
So, when the above code was run, the awk
read each line from the input.txt
; for every line, it matched the empty pattern, which was true
for all lines of input.txt
. Then, it ran the associated action and printed the value of the last field ($NF
).
The
awk
command will not remove the last space character from the read data.
Using sed
Command
Use the sed
command to get the last word of each line from a file in Bash.
1 2 3 4 5 6 7 |
It is line1 It is line2 It is line3 It is line4 It is line5 |
1 2 3 |
sed 's/.* //g' input.txt |
1 2 3 4 5 6 7 |
line1 line2 line3 line4 line5 |
We used the sed command, a stream editor, and a powerful utility for text manipulation. It processed each line individually and performed the specified actions based on the patterns.
The 's/.* //g'
was the substitution command, which followed the syntax s/pattern/replacement/flags
. Here, pattern represented the text to be matched in the read data, replacement meant the text to replace the matched pattern, and flags denoted the additional actions to be taken (if required).
In the pattern section, the .*
represented any number of characters excluding newline characters on the line. It matched the longest sequence of characters. In the replacement section, the //
indicated replacing the matched pattern with nothing, effectively removing it from the line.
In the flag section, the g
(for global) instructed the sed
command to apply the substitution globally to all pattern occurrences on the line. Remember that the input.txt
was the input file.
So, running the above code would read every line from the input.txt
file and apply the specified substitution globally to all pattern occurrences on every line. Note that each line would be processed individually, and sed
would remove all characters, including the last space character leaving the last word from each line.
You can use the same code to get the last word of each line from a file where the input file has the non-word characters; for instance, a question mark.
1 2 3 4 5 6 7 |
It is line1 Is it line2?? It is line3 It is line4! It is line5 |
1 2 3 |
sed 's/.* //g' input.txt |
1 2 3 4 5 6 7 |
line1 line2?? line3 line4! line5 |
Using cut
Command with rev
Use the cut
command to get the last word of each line from a file in Bash.
1 2 3 4 5 6 7 |
It is line1 It is line2 It is line3 It is line4 It is line5 |
1 2 3 |
rev input.txt | cut -d' ' -f1 | rev |
1 2 3 4 5 6 7 |
line1 line2 line3 line4 line5 |
The rev is a command-line utility that reverses every line’s characters. It takes input from the file or standard input and reverses the order of characters within each line. In the above case, the rev
took input from an input.txt
file.
This reversed data was passed to the cut
command via pipeline (|
). The cut
is a command-line tool which extracts sections from the lines of the given file or the standard input. It allows us to specify a delimiter and choose specific fields (columns) from the input.
We used the -d
option to mention a delimiter as -d' '
. In this case, the delimiter was a space character indicating that the input would be split into fields based on spaces. The -f1
was used to specify the field(s) to extract using the cut
command.
We specified 1
as a field number, meaning to extract the first column/field after splitting the input via a given delimiter.
So, when we ran the above code, the rev
command read data from the input.txt
and reversed the characters of every line. The cut
command received this data via pipeline and split it into fields using the given delimiter.
After splitting, the cut
command selected the first column using -f1
, corresponding to the original line’s last word. Note that we are still working on reversed data.
These chosen last word was passed to the second rev
command via a pipe, which reversed the characters again for every word to bring them into their original orientation.
You can use the same code to get the last word of each line from a file where the input file has the non-word characters; for instance, a question mark.
1 2 3 4 5 6 7 |
It is line1 Is it line2?? It is line3 It is line4! It is line5 |
1 2 3 |
rev input.txt | cut -d' ' -f1 | rev |
1 2 3 4 5 6 7 |
line1 line2?? line3 line4! line5 |
Using grep
Command
Use the grep
command to retrieve the last word from each line in Bash.
1 2 3 4 5 6 7 |
It is line1 It is line2 It is line3 It is line4 It is line5 |
1 2 3 |
grep -o "\w*$" input.txt |
1 2 3 4 5 6 7 |
line1 line2 line3 line4 line5 |
Here, we used the grep
command, a command-line tool, to search for the patterns within the input streams or files. It matched the lines containing the specified pattern and printed as an output on the Bash console.
We used the -o
option only to extract and display the matched part of every line rather than the whole line. The "\w*$"
was the pattern that grep
searched for in the given input.
In this pattern, the \w*
matched the zero or more word characters, while the $
matched the end of the line. So, using \w*
and $
together ensured that the grep
matched and selected the last word from each line of the input file (input.txt
).
The word character includes the digits, alphabetic characters, and an underscore. However, the above code using the grep
command will not work if the input file contains non-word characters. Let’s see how we can do it.
Use the grep
command as follows to get the last word of each line from a file where the input file has the non-word characters; for instance, a question mark.
1 2 3 4 5 6 7 |
It is line1 Is it line2?? It is line3 It is line4! It is line5 |
1 2 3 |
grep -o "[^[:space:]]*$" input.txt |
1 2 3 4 5 6 7 |
line1 line2?? line3 line4! line5 |
In this example, the grep -o "[^[:space:]]*$" input.txt
command printed the last word of each line in the input.txt
file.
We already learned about the grep
command and -o
option. The regular expression [^[:space:]]*$
matched any non-space characters at the end of every line. The ^
character inside the square brackets means not, so [^[:space:]]
matched any character that is not a space.
After the square brackets, the *
character means zero or more, so [^[:space:]]*
matched any sequence of non-space characters. The $
character at the end of the regular expression means end of line, so [^[:space:]]*$
matched any sequence of non-space characters at the end of each line
Using while
Loop with Parameter Expansion
Use the while
loop with parameter expansion to get the last word of each line from a file in Bash.
1 2 3 4 5 6 7 |
It is line1 It is line2 It is line3 It is line4 It is line5 |
1 2 3 4 5 6 |
while read -r -a current_line || [ -n "{current_line}" ] do echo "{current_line[-1]}" done < input.txt |
1 2 3 4 5 6 7 |
line1 line2 line3 line4 line5 |
Loops are essential when executing a set of commands for a particular thing. We used a while
loop to repeatedly run the set of commands as long as the given condition is true
.
The read
read the input lines and assigned values to the specified variable. The -r
option prevented the interpretation of backslashes and ensured that they were read as literal characters. On the other hand, the -a current_line
assigned the input fields (words) to an array variable called current_line
.
Here, you should ask how a line was converted into an array of words. What was the delimiter?
Remember, the read
command uses the default value of the IFS
variable as a delimiter, which is a space character. When using the read
command, the IFS
determines how the input would split into words (fields).
You need to mutate the
IFS
variable explicitly if you want to use anything other than space as the delimiter.
Moving forward, the || [ -n "{current_line}" ]
was a logical OR (||
) condition ensuring the loop continued even if the read
command encountered the end of the given file. Here, -n "{current_line}"
checked if the current_line
variable was non-empty. If it was, the condition was considered true
, and the loop continued.
Then, inside the loop, we used an echo
command to print the last element of the current_line
. The last element was captured using parameter expansion syntax as ${current_line[-1]}
; here -1
was the negative index, which counted from the end of the array.
In the above example, the do
and done
marked the start and end of the while
loop. The data processed within the loop was passed using the redirection operator (<
).
So, executing the above code would read the input.txt
file line by line, split each line into words using space as a delimiter, and assign the words array to the current_line
. If the current_line
was not empty, we echoed the last element of the current_line
array; otherwise, the loop would continue.
This process would be repeated until all lines of the input.txt
file had been processed.
You can use the same code to get the last word of each line from a file where the input file has the non-word characters; for instance, a question mark.
1 2 3 4 5 6 7 |
It is line1 Is it line2?? It is line3 It is line4! It is line5 |
1 2 3 4 5 6 |
while read -r -a current_line || [ -n "{current_line}" ] do echo "{current_line[-1]}" done < input.txt |
1 2 3 4 5 6 7 |
line1 line2?? line3 line4! line5 |
That’s all about how to get last word in each line in Bash.