24

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
  • 92,097
  • 6
  • 117
  • 207
user613114
  • 2,641
  • 11
  • 42
  • 70

4 Answers4

48

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
  • 92,097
  • 6
  • 117
  • 207
  • 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
  • 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
  • 13,978
  • 10
  • 59
  • 92
5

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

sed -r 's/(_[^_]+){2}$//g'
Shiplu Mokaddim
  • 54,465
  • 14
  • 131
  • 183
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
  • 4,119
  • 23
  • 44
Rahul
  • 2,154
  • 3
  • 19
  • 29