views:

10227

answers:

9

Given a string file path such as "/foo/fizzbuzz.bar" how would I use bash to extract just the "fizzbuzz" portion of said string?

+13  A: 

look at the basename command:

NAME=`basename /foo/fizzbuzz.bar .bar`
zigdon
Probably the simplest of all the currently offered solutions... although I'd use $(...) instead of backticks.
Michael Johnson
Simplest but adds a dependency (not a huge or weird one, I admit). It also needs to know the suffix.
Vinko Vrsalovic
+5  A: 

Pure bash way:

~$ x="/foo/bar/fizzbuzz.bar.quux.zoom"; 
~$ y=${x/\/*\//}; 
~$ echo ${y/.*/}; 
fizzbuzz

This functionality is explained on man bash under "Parameter Expansion". Non bash ways abound: awk, perl, sed and so on.

EDIT: Works with more than one dot on filenames and doesn't need to know the suffix (extension)

Vinko Vrsalovic
Highlighting FAIL!
Vinko Vrsalovic
A: 
perl -pe 's/\..*$//;s{^.*/}{}'
mopoke
+2  A: 

The basename and dirname functions are what you're after:

mystring=/foo/fizzbuzz.bar
echo basename: $(basename $mystring)
echo basename + remove .bar: $(basename $mystring .bar)
echo dirname: $(dirname $mystring)

Has output:

basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
Jerub
+17  A: 

Here's how to do it with the # and % operators in Bash.

$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz

${x%.bar} could also be ${x%.*} to remove everything after a dot or ${x%%.*} to remove everything after the first dot.

Example:

$ x="/foo/fizzbuzz.bar.quux"
$ y=${x%.*}
$ echo $y
/foo/fizzbuzz.bar
$ y=${x%%.*}
$ echo $y
/foo/fizzbuzz
Zan Lynx
I ended up using this one because it was the most flexible and there were a couple other similar things I wanted to do as well that this did nicely.
Lawrence Johnston
+1  A: 

Using basename assumes that you know what the file extension is, doesn't it?

And I believe that the various regular expression suggestions don't cope with a filename containing more than one "."

The following seems to cope with double dots. Oh, and filenames that contain a "/" themselves (just for kicks)

To paraphrase Pascal, "Sorry this script is so long. I didn't have time to make it shorter"


  #!/usr/bin/perl
  $fullname = $ARGV[0];
  ($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
  ($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
  print $basename . "\n";
 
Andrew Edgecombe
A: 

If you can't use basename as suggested in other posts, you can always use sed. Here is an (ugly) example. It isn't the greatest, but it works by extracting the wanted string and replacing the input with the wanted string.

echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'

Which will get you the output

fizzbuzz

nymacro
A: 

The basename does that, removes the path. It will also remove the suffix if given and if it matches the suffix of the file but you would need to know the suffix to give to the command. Otherwise you can use mv and figure out what the new name should be some other way.

waynecolvin
A: 

Beware of the suggested perl solution: it removes anything after the first dot.

$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some

If you want to do it with perl, this works:

$ echo some.file.with.dots | perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with

But if you are using Bash, the solutions with y=${x%.*} (or basename "$x" .ext if you know the extension) are much simpler.

mivk