I have a directory with automatically generated files that all end with the .sample extension. I would like to have a way to remove the .sample extension from them all in one terminal command.

I tried this:

mv ./{$1}*.sample ./$1

But it doesn't work because I'm definitely placing the {$1} in the wrong place or way. Can anyone point to the right direction?

Thanks in advance.


One of the many way to do that:

for i in *.sample; do NEWNAME=`echo "$i" | sed 's/\.sample//'`; mv "$i" "$NEWNAME"; done
  • 1
    basename is more appropriate; besides your code is wrong: it will croak on filenames with space
    – niXar
    Sep 12 '09 at 17:37
  • Corrected for space problem
    – radius
    Sep 12 '09 at 17:44
  • 2
    This has a few other pathological problems as well. Consider what happens if a file is named '*.sample' or 'foo.sample.sample'. See Mark Drayton's solution.
    – D.Shawley
    Sep 12 '09 at 18:10
  • It fails for file names with multiple spaces, e.g. a b.sample. You should use echo "$i" instead of echo $i. Sep 12 '09 at 19:13
  • Thanks Cristian, correted. @rogeriopvl you should probably accept markdrayton answer, so that I could suppress my not so good solution.
    – radius
    Sep 12 '09 at 19:26
$ touch {a,b,c,"white space"}.sample

$ ls *.sample
a.sample        c.sample
b.sample        white space.sample

$ for SAMPLE in *.sample; do mv -v "$SAMPLE" "${SAMPLE%.sample}"; done
a.sample -> a
b.sample -> b
c.sample -> c
white space.sample -> white space

Edit: Also see ${parameter#word}, which deletes word from the front of parameter:

$ FILENAME=140909_stats_report.txt
$ echo "${FILENAME#140909_}"

I remember which of these I need from the positions of the # and % keys on my (UK) keyboard: # is left of % so matches on the left. Before I noticed that I had to check the man page every time :~)

These expansions also support shell wildcards:

$ echo "${FILENAME%.*}"

The # and % forms match the shortest expansion of word. You can use ## or %% for the longest match. E.g.:

$ FILENAME=140909_stats_report.txt
$ echo "${FILENAME#*_}"  # match as little as possible
$ echo "${FILENAME##*_}" # match as much as possible

It's worth getting to grips with these expansions. There's several more, including (somewhat cranky) regex support, substrings and ways to set defaults or get variable lengths. Man bash, of course.

  • 3
    +1 - using the bash parameter substitution is the best solution. No unnecessary processes are spawned and the result is very clean.
    – D.Shawley
    Sep 12 '09 at 18:03
for n in *.sample ; do mv "$n" "$(basename "$n" .sample)" ; done

The rename command accepts Perl expressions:

rename 's/\.sample$//' *.sample


$ ls *sample*
file0.sample  file2.sample  foo.sample.sample
file1.sample  file3.sample  with space.sample
$ rename 's/\.sample$//' *.sample
$ ls *sample*

On my Ubuntu system, rename is symlinked to the prename script from the perl package.

rename '.sample' '' *.sample

On Fedora, the rename command is included in the util-linux-ng package.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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