Removing extensions in a column

awksedtext processing

I have a file like this

ILMN_1343291    TGTGTTGAGAGCTTCTCAGACTATCCACCTTTGGGTCGCTTTGCTGTTCG  NM_001402.5
ILMN_1343295    CTTCAACAGCGACACCCACTCCTCCACCTTTGACGCTGGGGCTGGCATTG  NM_002046.3
ILMN_1651209    TCACGGCGTACGCCCTCATGGGGAAAATCTCCCCGGTGACTTTCAGGTCC  NM_182838.1

I want to remove the numeric extensions from the end in the 3rd column so that my output file looks like this

ILMN_1343291    TGTGTTGAGAGCTTCTCAGACTATCCACCTTTGGGTCGCTTTGCTGTTCG  NM_001402
ILMN_1343295    CTTCAACAGCGACACCCACTCCTCCACCTTTGACGCTGGGGCTGGCATTG  NM_002046
ILMN_1651209    TCACGGCGTACGCCCTCATGGGGAAAATCTCCCCGGTGACTTTCAGGTCC  NM_182838

How can I do it on command line preferably using awk? I can do this in perl but I am pretty sure there is a single command line to do it.

Best Answer

With awk:

awk -F'.' '{print $1}' file

-F option change default field separator(space) to dot(.).
$1 is index of field position(with . field separator).

{ILMN_1343291    TGTGTTGAGAGCTTCTCAGACTATCCACCTTTGGGTCGCTTTGCTGTTCG  NM_001402}.{5}
                  ^^ field index is $1                                          ^^$2

With rev and awk:

rev file | awk -F'.' '{print $2}'|rev # reverse characters of each lines,\
                                        print field number 2 with (.) separator \
                                        and reverse the result again

The rev utility copies the specified files to standard output, reversing the order of characters in every line. If no files are specified, standard input is read.

With sed:

sed 's/.[0-9]*$//' file

sed 's/.[^.]*$//' file

$ point to end of line. In first sed command search for char(.) which followed by zero or more occurrences of numbers and replace them with whitespace.

In second sed command remove everything that followed by (.) and also remove dot(.) itself.

With rev and sed:

rev file| sed 's/.*[.]//' |rev

Delete everything before dot(.) Also include and remove . itself.

With grep:

grep -oP '.*(?=\.[0-9])' file
    -o, --only-matching
          Print only the matched (non-empty) parts of a matching line,
          with each such part on a separate output line.
    -P, --perl-regexp
          Interpret PATTERN as a Perl compatible regular expression (PCRE)

(?=pattern): Positive Lookahead: The positive lookahead construct is a pair of parentheses, with the opening parenthesis followed by a question mark and an equals sign.

.*(?=\.[0-9]): (positive lookahead) matches everything(.*) followed by one dot(.) and any occurrences of numbers, without making the pattern(\.[0-9]) part of the match.

With rev and grep:

rev file |grep -oP '(?<=[0-9]\.).*' |rev

rev file |grep -oP '[0-9]\.\K.*' |rev

(?<=pattern): Positive Lookbehind. A pair of parentheses, with the opening parenthesis followed by a question mark, "less than" symbol, and an equals sign.

(?<=[0-9]\.).* (positive lookbehind) matches everything which followed by any occurrences of numbers and end with dot(.).

In second grep command, you can use the nifty \K in place of the lookbehind assertion.

With cut:

cut -f1 -d. file

cut -c 1-77 file # Print first 77 characters of each line.
cut - remove sections from each line of files

-d, --delimiter=DELIM
      use DELIM instead of TAB for field delimiter

-f, --fields=LIST
      select  only  these  fields;

-c, --characters=LIST
      select only these characters

With while loop:

while read line; do echo "${line::-2}";done <file

This will work if you have only number with length=1 at the end of each lines and they are fix length. above command remove last two character at the end of every lines in input file. alternative commands is ${line%??}.