1

I was wondering if I could use sed or grep (but no -P flag) to give the same functionality as awk '{print $6}'.

I am making a script for iOS, but I don't want to have to install any 3rd party commands (like awk).

  • The grep on iOS also doesn't support the -P flag, so no perl-regexp.
  • cut is a 3rd-party command on iOS (so no cut)
6

If you have a string in a variable in a script and you'd like to extract the last field (as you say in the title of the question), then you may do

field=${string##* }

This assumes that the string in $string is space-separated (change the space in the above variable substitution to whatever delimiter you're using). The ${variable##pattern} variable substitution removes the longest prefix string from $variable that is matching the given pattern.

With sed on a file, the following would extract the last whitespace-separated field of each line:

sed 's/^.*[[:space:]]//' data.in

It does this by deleting everything up to and including the last whitespace character on each line. Change [[:space:]] to a regular expression that matches the delimiter before the last column if your data does not use tabs or spaces as delimiter.

  • Thanks for the reply. Your answer works on Linux, but cut is a 3rd party command on iOS. +1 anyway :) – Jacob Collins Feb 5 '18 at 7:57
  • 1
    @JacobCollins See the edited version by the author. Also, note that first solution (${variable##* } part) involves shell operation that is specified by POSIX standard, which in other words means it should work pretty much anywhere, including iOS. – Sergiy Kolodyazhnyy Feb 5 '18 at 8:31
3

To get the last blank-delimited column with a POSIX compliant sed (the equivalent of awk '{print $NF}') and assuming the input is valid text:

sed 's/[[:blank:]]*$//; # remove trailing blanks
     s/.*[[:blank:]]//; # remove every thing up to the last blank
    ' < file

Note that most awk implementations separate fields on blanks (horizontal spacing), but some (namely busybox awk) separate on all spaces ([[:space:]]), and some only on the ASCII blanks (space and tab) regardless of the locale. On files coming from Microsoft OSes, you may want to replace [[:blank:]] with [[:space:]] so it considers the trailing CR character as spacing and discards it.

To get the sixth field (equivalent of awk '{print $6}'):

s='[[:blank:]]' S='[^[:blank:]]'
sed "s/^$s*\($S\{1,\}$s\{1,\}\)\{5\}\($S\{1,\}\).*/\2/; t
     s/.*//; # flush the line if does not have 6 fields"

You could also use an approach like:

sed 's/[^[:blank:]]\{1,\}/\
&\
/6; s/.*\n\(.*\)\n.*/\1/;t
s/.*//'
2

With grep, assuming -o option is available (also, going by title that last column is needed, not just particular column)

$ echo 'foo bar 123' | grep -o '[^ ]*$'
123
$ echo 'foo;bar;123' | grep -o '[^;]*$'
123
0

One could do something like this:

$ var="This is a string"; printf "%s\n" $var | { while read -r line; do  last="$line"; done; printf "%s\n" "$last"; }
string

This takes advantage of word-splitting and printf's ability to keep fitting arguments to format string even if their number doesn't match. That allows us to transform each word or field of string into separate lines. That is coupled with standard while read -r variable; do...done loop for reading stdin stream line by line, where we just get last line, aka last field.

This is whole lot of acrobatics but it is a shell approach that doesn't rely on external tools. However for really portable and proper shell-only way, Kusalananda's answer is still better.

  • 1
    That assumes $var doesn't contain wildcards and that $IFS has not been modified. – Stéphane Chazelas Feb 5 '18 at 9:30
  • Or use a bash array (with same caveats about IFS and glob) a=($var); printf '%s\n' ${a[${#a[@]}-1]} (or in recent bash just ${a[-1]}) or if you don't need to preserve positional params or else localize them with a function or subshell set -- $var; printf '%s\n' ${!#} or in poorer shells ... shift $(( $#-1 )); printf '%s\n' "$1" or yuckily ... eval printf '%s\\n' \"\${$#}\" – dave_thompson_085 Feb 5 '18 at 15:40
0

I tested for below case with space delimitter to print last column using sed command and it worked fine

input.txt

praveen ajay abhi

Method1

echo "praveen ajay abhi"| sed -r "s/.* //g"

output

abhi

  • -r is a GNU extension and is not needed here. On BSDs, -E is more common to enable extended regular expressions. The g flag is also superfluous as the regex can only match once here (assuming valid text input). Note that like many other answers here, it doesn't work on the output of echo " first second last " (with more blanks after the last field) – Stéphane Chazelas Feb 5 '18 at 11:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.