0

How to print the last field (word3,a,b,c,d,e), that contains the field separator ,?

  • in each line we have only 3 words/strings as the following structure

    type,parameter,value

but the value can include the unescaped field separator itself. Example from line:

echo word1,word2,word3,a,b,c,d,e | awk -F "," '{print $3}'

its print:

word3

expected results:

word3,a,b,c,d,e

other example

echo 32637,921763.373,str84,str42,struj,str56,str65 | awk -F "," '{print $3}'

expected results:

str84,str42,struj,str56,str65 
  • 2
    Sounds like a job for cut: echo word1,word2,word3,a,b,c,d,e | cut -d, -f3- – cuonglm Aug 17 '17 at 8:13
  • ok go on it please publish your answer – yael Aug 17 '17 at 8:15
2

Well, the last field in word1,word2,word3,a,b,c,d,e is e and the third field is word3. It looks like you want the part of the line starting with the third field. It's easier with cut:

$ echo word1,word2,word3,a,b,c,d,e | cut -d , -f 3-
word3,a,b,c,d,e

-f 3- is -f x-y for fields x to y, but with y omitted, so it's from 3rd to last field.

Note that it assumes the lines contain at least 3 fields. It would give empty output lines for input lines that contain 2 fields, and leave the line untouched if it contained no comma (you can add a -s option to skip the non-delimited lines):

$ printf '%s\n' a a,b a,b,c a,b,c,d | cut -d , -f 3-
a

c
c,d
$ printf '%s\n' a a,b a,b,c a,b,c,d | cut -sd , -f 3-

c
c,d

With awk, you could do:

$ printf '%s\n' a a,b a,b,c a,b,c,d | awk 'sub(/^[^,]*,[^,]*,/, "")'
c
c,d

(the awk 'sub(/^([^,]*,){2}/, "")' variant, though POSIX, is less portable as there are still a few awk implementations that don't support the {x,y} regexp operator)

To delete the first 2 fields (and only print the lines where they have been removed), though that would be using awk as a glorified sed as that's the same as sed -n 's/^[^,]*,[^,]*,//p'.

Or:

$ printf '%s\n' a a,b a,b,c a,b,c,d | awk 'sub(/^[^,]*,?[^,]*,?/, "")'


c
c,d

to print an empty line for lines that have fewer than 3 fields.

2

The awk way would be:

awk -F "," '{for(i=3;i<NF;i++)printf("%s,", $i);print $NF}'

But it sounds like a job for cut:

cut -d , -f 3-
1

With perl, making use of its array-slice feature (avoiding the need for a for loop as in awk):

$ echo word1,word2,word3,a,b,c,d,e | perl -F, -lane 'print join(",",@F[2..$#F])'
word3,a,b,c,d,e

Explanation of perl command-line options used (see man perlrun for more details):

  • -F, set field separator for autosplit to ,
  • -l enables automatic line-ending processing (i.e. automatically strip newlines from the end of each input line and add them to each print-ed output line).
  • -a turn on autosplit mode - each input line is automatically split into an array @F.
  • -n read and process each line of stdin and/or any filename arguments (essentially, a while(<>) loop around the entire script)
  • -e execute the next argument (the quoted string) as a perl script.

Note: perl arrays are zero-based, not one-based, so the third field is array element 2, not 3 (that is, @F[2], not @F[3]).

$#F is the index number of the final element of array @F, so @F[2..$#F] means "all elements of the array @F from the third to the last".


BTW, there is another option -p which is very similar to -n except that at the end of each pass through the while(<>) loop, it also prints the input line. If the input line has been modified by any prior statements then the line is printed as modified.

One of the uses for this is that it allows you to write very sed-like scripts in perl (but with all the features and syntactic sugar of perl in addition to sed). e.g. perl -pe 's/foo/bar/g' and sed -e 's/foo/bar/g' will have identical output given the same input.

Similarly, -n combined with -a makes it easy to write very awk-like scripts. In fact, perl -lane is pretty much the standard way to write an awk-like one-liner with perl.

One of the strengths of perl is that it combines the features of sed and of awk (and of tr) and a whole lot more, including access to a huge library of modules called the "Comprehensive Perl Archive Network" or CPAN

0

With this you're done

echo 32637,921763.373,str84,str42,struj,str56,str65 | awk -F "," '{ for(i = 3; i < NF+1; i++) printf "%s%s",$i,(i!=NF?",":"");}'

but anyway, you need to read awk docs.

0

Using sed:

sed 's/^\([^,]*,\)\{0,2\}//' <<<"$line"

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.