Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I've asked almost the same question already, but this time, I want to retrieve the X latest elements of a row of a CSV file. For example, with an input file as this one:

1;foo;bar;baz;x;y;z
2;foo;bar;baz;x;y;z
3;foo;bar;baz;x;y;z

What would be the command (eventually using cut) to get the last 2 columns, so I get:

y;z
y;z
y;z

In fact, my real target is to retrieve the first 3 and the last 2 fields of each row, so I get:

1;foo;bar;y;z
2;foo;bar;y;z
3;foo;bar;y;z

Unfortunately, I cannot use a command like cut -d \; -f 1-3,10-11 (if there are 11 elements in the row), because the CSV file does not respect the real CSV format. Indeed, some fields in the middle of the rows are encrypted, and their encrypted value may sometimes contains a ; characters (and of course, they are not wrapped inside "). In others words, my lines may look like that:

1;foo;bar;#@$"é&^l#;baz;x;y;z
2;foo;bar;#¤=é;)o'#;baz;x;y;z
3;foo;bar;#]]'~é{{#;baz;x;y;z

and as you can see, on the second line, there is an additional ; character, so I can't use here a command like cut -d \; -f 1-3,7-8, because if will return that, which is wrong:

1;foo;bar;y;z
2;foo;bar;x;y  (-> Wrong here, there is a shift)
3;foo;bar;y;z

So how can I use cut to solve my problem?

Thanks

ps: I am specially in love with the cut command, so if you have a command that does what I want but that is not cut, then it's fine too :)

Edit It seems important to note that the machine is quite old: uname -a give this message:

SunOS ###### 5.10 Generic_142900-05 sun4u sparc SUNW,Sun-Fire-V240

and some commands may not be present (like rev)

share|improve this question
    
If your file has fixed width fields, you can use the -b option to select items via byte or -c for characters, rather than -f. –  ernie Jan 7 '13 at 21:35
add comment

3 Answers

up vote 5 down vote accepted

On your version of SunOS nawk(or for that matter awk) should be able to do the trick

 nawk -F';' 'BEGIN{OFS=";"}{print($1,$2,$3,$(NF-1),$(NF))}' file.txt 
share|improve this answer
    
Thanks a lot. It's working :) –  romaintaz Jan 7 '13 at 16:35
add comment

Here is a multiple-command solution for retrieving the first 3 and the last 2 fields using only cut, rev (for reversing) and shell-builtins:

while read line
do
    first=$(echo -n "$line" | cut -d ";" -f -3)
    second=$(echo -n "$line" | rev | cut -d ";" -f -2 | rev)
    echo "$first;$second"
done < my_file

These statements can also be put into a single line, of course.

EDIT:

I gathered some one-line alternatives to rev (which omit printing the final '\n'):

python: python -c "import sys; sys.stdout.write(raw_input()[::-1])

perl: perl -ne 'chomp;print scalar reverse;'

and there are a lot more possibilities for reversing a string. Maybe some of those work on your system.

share|improve this answer
    
Argh. Your solution seems interesting, but unfortunately, the command rev is not installed on my server (SunOS 5.10) –  romaintaz Jan 7 '13 at 14:59
    
@romaintaz Too bad, my rev comes from the util-linux package which contains various essential commands for Linux. I wonder whether SunOS has a similar command. –  scai Jan 7 '13 at 15:01
add comment
% cat a
1;foo;bar;#@$"é&^l#;baz;x;y;z
2;foo;bar;#¤=é;)o'#;baz;x;y;z
3;foo;bar;#]]'~é{{#;baz;x;y;z
% sed -r 's,^(([^;]+;){3}).*;([^;]+;[^;]+)$,\1\3,' < a
1;foo;bar;y;z
2;foo;bar;y;z
3;foo;bar;y;z
share|improve this answer
    
I fear that my version of sed is too old, as your command is throwing a sed: illegal option -- r message :( –  romaintaz Jan 7 '13 at 15:00
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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