Reputation: 33
I have a bash script where I am using grep to get every line that contains a certain date:
(grep -h "$date" $1) > requests.txt
an example line being..
95.81.72.148 - - [22/Jan/2019:08:01:41 +0330] "GET /image/5384/productModel/100x100 HTTP/1.1" 200 2280 "https://link" "Mozilla/5.0 (Windows NT 6.1; rv:60.0) IPADRESS Firefox/60.0" "-"
However I want to use piping and cut to somehow only store the IPADRESS of each line in the text file (the second to last word in the line)
How would I do this?
Upvotes: 2
Views: 2187
Reputation: 117
A pure portable POSIX shell solution is to reverse the words in the line and then output the second word:
#!/bin/sh
LINE="foo * bar * myword lastword"
REV= && for _ in $LINE; do REV="$_ $REV"; done
set -f && set +f -- $REV
echo $2
This will output myword
.
A handy oneliner function is:
#!/bin/sh
x() { local rev="" line="$1"; for _ in $line; do rev="$_ $rev"; done; set -f && set +f -- $rev; echo $2; }
so you can call it like:
x "AA BB CC DD"
CC
Hint: the $_
is just used as a throwaway variable.
Hint: the idea is from https://stackoverflow.com/a/71129132/5688306
Upvotes: 0
Reputation: 4969
You ask how to do it with cut
, and you get answers that tell you to use awk
or perl
:-). Of course you can do this with cut
too:
rev |cut -d' ' -f3 | rev
This fails if the last two "words" contain spaces. But then, so do the perl
and awk
solutions.
Upvotes: 3
Reputation: 12347
Use this Perl one-liner, which prints field number 3 counting from the end (last field being $F[-1]
):
perl -lane 'print $F[-3]'
Example:
echo '95.81.72.148 - - [22/Jan/2019:08:01:41 +0330] "GET /image/5384/productModel/100x100 HTTP/1.1" 200 2280 "https://link" "Mozilla/5.0 (Windows NT 6.1; rv:60.0) IPADRESS Firefox/60.0" "-"' | \
perl -lane 'print $F[-3]'
Output:
IPADRESS
The Perl one-liner uses these command line flags:
-e
: Tells Perl to look for code in-line, instead of in a file.
-n
: Loop over the input one line at a time, assigning it to $_
by default.
-l
: Strip the input line separator ("\n"
on *NIX by default) before executing the code in-line, and append it when printing.
-a
: Split $_
into array @F
on whitespace or on the regex specified in -F
option.
SEE ALSO:
perldoc perlrun
: how to execute the Perl interpreter: command line switches
BTW, cut
is not the right tool for this task, because in cut
, fields are numbered from the start. Meanwhile, in many scripting languages, such as Perl and awk, there is a method to split the line on whitespace, and count the fields from either the start or the end.
Upvotes: 0
Reputation: 531165
awk
would be simpler, and it also subsumes the use of grep
.
awk -v d="$date" '$0 ~ d { print $(NF - 2) }' "$1" > requests.txt
Upvotes: 3