0

I have files which all look like this: filename.bla_1

of cours I cannot know if the filename has "_" in it. could be file_name.bla_1. I want to write a function that take filename and delete the _# at the end. filename.bla_1 will be --> filename.bla

echo $filename | rev | cut -d "_" -f2 | rev

will do the trick if the file doesn't have "" in the name but I want to make sure this works also for filenames with ""

3
  • How about simply using ' instead of " for your delimeter string?echo $filename | rev | cut -d '_' -f2 | rev seems to do the job for me, with filenames containing both " and '.
    – mijiturka
    Commented Jun 15, 2021 at 17:36
  • @mijiturka why not post that as an answer instead of comment since it solves the OP's question?
    – pitprok
    Commented Jun 15, 2021 at 18:39
  • @pitprok Just because it's a small change to OP's code, and choroba's (better) answer was already there when I did.
    – mijiturka
    Commented Jun 15, 2021 at 18:56

3 Answers 3

6

You can use parameter expansion. The % removes the shortest possible pattern on the right side of the value, ## removes the longest possible match on the left:

#! /bin/bash
for f in filename.bla_1 \
         file_name_with_underscores.foo_2 \
         file_name_with_underscores.foo \
         filename.with_dots.foo_2 ; do
    ext=${f##*.}
    basename=${f%.*}
    echo "$basename.${ext%_*}"
done
2
  • If a file with the name "file_name_with_underscores.foo" is passed through this, it will end up as "file_name_with". This needs editing so the _ part will only be deleted if it's found after the extension.
    – pitprok
    Commented Jun 15, 2021 at 18:36
  • @pitprok: Updated to handle such filenames, too.
    – choroba
    Commented Jun 15, 2021 at 18:48
1

If you care to tweak the globbing parser a little,

shopt -s extglob
for f in abc.bla a_b_c_.bla abc.bla_1 a_b_c_.bla_2 123.456.789 123.456.789_x abc_ 
do echo ${f%_+([^._])}
done
abc.bla
a_b_c_.bla
abc.bla
a_b_c_.bla
123.456.789
123.456.789
abc_

${f%_+([^._])} means the value of $f with a _ followed immediately by one or more non-dot-or-underscore characters trimmed OFF the end.

1
0

Use @choroba's answer.

But to fix your code, after you reverse the filename, you need to take the 2nd and all following fields, not just the 2nd:

$ filename=foo_bar_baz.bla_1
$ rev <<<"$filename" | cut -d_ -f2- | rev
foo_bar_baz.bla

The -f2- with the trailing hyphen is the magic here. Read the cut man page.

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