26

I'm trying to parse file names in specific directory. Filenames are of format:

token1_token2_token3_token(N-1)_token(N).sh

I need to cut the tokens using delimiter '_', and need to take string except the last two tokens. In above examlpe output should be token1_token2_token3.

The number of tokens is not fixed. I've tried to do it with -f#- option of cut command, but did not find any solution. Any ideas?

ysth
  • 96,171
  • 6
  • 121
  • 214
user613114
  • 2,731
  • 11
  • 47
  • 73

4 Answers4

52

With cut:

$ echo t1_t2_t3_tn1_tn2.sh | rev | cut -d_ -f3- | rev
t1_t2_t3

rev reverses each line. The 3- in -f3- means from the 3rd field to the end of the line (which is the beginning of the line through the third-to-last field in the unreversed text).

ysth
  • 96,171
  • 6
  • 121
  • 214
  • This works like a charm :D And yes as asked in the question it uses cut command. I will choose this answer. – user613114 Dec 23 '12 at 15:56
  • Answered my question http://stackoverflow.com/questions/17644000/how-to-get-second-last-field-from-a-cut-command/17644034?noredirect=1#17644034 too. Thanks – Archit Jain Jul 14 '13 at 21:40
  • I fell in love with this answer. I keep forgetting about the existance of rev. – norbitheeviljester Nov 14 '15 at 08:56
  • 1
    Wonderful! Worked with bash for 20 years, never knew about rev. – Sasha Pachev Dec 07 '18 at 00:16
  • what if you don't know how many tokens there will be and you want all but the last one? – Michael Sep 26 '20 at 19:06
  • @Michael then do `| rev | cut -d_ -f2- | rev`. 2- is second field through last field in the reversed text, which is first field through next-to-last field in the original text – ysth Sep 27 '20 at 04:28
7

You may use POSIX defined parameter substitution:

$ name="t1_t2_t3_tn1_tn2.sh"
$ name=${name%_*_*}
$ echo $name
t1_t2_t3
Rubens
  • 14,478
  • 11
  • 63
  • 92
6

It can not be done with cut, However, you can use sed

sed -r 's/(_[^_]+){2}$//g'
Shiplu Mokaddim
  • 56,364
  • 17
  • 141
  • 187
1

Just a different way to write ysth's answer :

echo "t1_t2_t3_tn1_tn2.sh" |rev| cut -d"_" -f1,2 --complement | rev
Nicolas Pepinster
  • 5,413
  • 2
  • 30
  • 48
Rahul
  • 2,354
  • 3
  • 21
  • 30