Insert the name of file inside the file

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


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

$ x="/foo/"
$ y=${}
$ echo ${y##*/}

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


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

look at the basename command:

NAME=`basename /foo/ .bar`

Pure bash, done in two separate operations:

  1. Remove the path from a path-string:
    #$file is now 'file.gif'
  2. Remove the extension from a path-string:
    #${base} is now 'file'.

Pure bash way:

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

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

EDIT: Works with dots in file suffixes and doesn't need to know the suffix (extension), but doesn’t work with dots in the name itself.

Using basename I used the following to achieve this:

for file in *; do
    fname=`basename $file $ext`

    # Do things with $fname

This requires no a priori knowledge of the file extension and works even when you have a filename that has dots in it's filename (in front of it's extension); it does require the program basename though, but this is part of the GNU coreutils so it should ship with any distro.

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

echo basename: $(basename $mystring)
echo basename + remove .bar: $(basename $mystring .bar)
echo dirname: $(dirname $mystring)

Has output:

basename + remove .bar: fizzbuzz
dirname: /foo

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"

  $fullname = $ARGV[0];
  ($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
  ($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
  print $basename . "\n";

perl -pe 's/\..*$//;s{^.*/}{}'

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/' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'

Which will get you the output


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

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

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

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

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

Combining the top-rated answer with the second-top-rated answer to get the filename without the full path:

$ x="/foo/"
$ y=(`basename ${x%%.*}`)
$ echo $y

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.

Category: bash Time: 2008-09-24 Views: 1

Related post

iOS development

Android development

Python development

JAVA development

Development language

PHP development

Ruby development


Front-end development


development tools

Open Platform

Javascript development

.NET development

cloud computing


Copyright (C), All Rights Reserved.

processed in 0.211 (s). 12 q(s)