Extract substring from a field with single awk in AIX

Viewed 397

I have a file file with content like:

stringa    8.0.1.2     stringx
stringb    12.01.0.0    stringx

I have to get a substring from field 2 (first two values with the dot).
I am currently doing cat file | awk '{print $2}' | awk -F. '{print $1"."$2}' and getting the expected output:

8.0
12.01

The query is how to do this with single awk?
I have tried with match() but not seeing an option for a back reference. Any help would be appreciated.

6 Answers

You can do something like this.

$ awk '{ split($2,str,"."); print str[1]"."str[2] }' file
8.0
12.01

Also, keep in mind that your cat is not needed. Simply give the file directly to awk.

With GNU grep please try following command once.

grep -oP '^\S+\s+\K[[:digit:]]+\.[[:digit:]]+' Input_file

Explanation: Using GNU grep here. Using its -oP options to print matched part and enable PCRE with -P option here. In main program, matching from starting non-space characters followed by 1 or more spaces, then using \K option to forget that match. Then matching 1 or more digits occurrences followed by a dot; which is further followed by digits. If a match is found then it prints matched value.

I would use GNU AWK's split function as follow, let file.txt content be

stringa    8.0.1.2     stringx
stringb    12.01.0.0    stringx

then

awk '{split($2,arr,".");print arr[1]"."arr[2]}' file.txt

output

8.0
12.01

Explantion: split at . 2nd field and put elements into array arr.

(tested in gawk 4.2.1)

You could match digits . digits from the second column and print if there is a match:

awk 'match($2, /^[[:digit:]]+\.[[:digit:]]+/) {
    print substr($2, RSTART, RLENGTH)
}
' file

Output

8.0
12.01

Also with GNU awk and gensub():

awk '{print gensub(/([[:digit:]]+[.][[:digit:]]+)(.*)/,"\\1","g",$2)}' file
8.0
12.01
  • gensub() provides the ability to specify components of a regexp in the replacement text using parentheses in the regexp to mark the components and then specifying \\n in the replacement text, where n is a digit from 1 to 9.

You should perhaps not use awk at all (or any other external program, for that matter) but rely on the field-splitting capabilities of the shell and some variable expansion. For instance:

 # printf "%s\n%s\n" "stringa    8.0.1.2     stringx" \
                     "stringb    12.01.0.0    stringx" |\
   while read first second third junk ; do
        printf "=%s= =%s= =%s=\n" "$first" "$second" "$third"
   done
   =stringa= =8.0.1.2= =stringx=
   =stringb= =12.01.0.0= =stringx=

As you can see the value is captured in the variable "$second" already and you just need to further isolate the parts you want to see - the first and second part separated by a dot. You can do that either with parameter expansion:

 # variable="8.0.1.2"
 # echo ${variable%.*.*}
   8.0

or like this:

 # variable="12.01.0.0"
 # echo ${variable%${variable#*.*.}}
   12.01

or you can use a further read-statement to separate the parts and then put them back together:

 # variable="12.01.0.0"
 # echo ${variable} | IFS=. read parta partb junk
 # echo ${parta}.${partb}
   12.01

So, putting all together:

 # printf "%s\n%s\n" "stringa    8.0.1.2     stringx" \
                     "stringb    12.01.0.0    stringx" |\
   while read first second third junk ; do
        printf "%s\n" "$second" | IFS=. read parta partb junk
        printf "%s.%s\n" "$parta" "$partb"
   done
   8.0
   12.01
Related