I wanted to delete all .sh extensions so did this:

ls *.sh | xargs -I {} mv {} `basename {} .sh`

However it doesn't work, it behaves like basename returns unchanged file name.

Why is it behaving that way ?

For instance, this works:

ls *.sh | xargs -I {} echo `basename {}.jpg .jpg`;


Solution: single quote prevents `basename ...` evaluation by the shell before the command is run.

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'

Because the basename command is run before the pipeline is run. To make this work you need xargs to execute basename and you can do that with sh -c, e.g.:

ls *.sh | xargs -L1 sh -c 'basename $1 .sh' dummy


  • If you don't tell xargs where to insert the file names they will be added at the end of the command line.
  • You should use the -L1 switch or its equivalent, so xargs only passes one argument to sh.
  • Using the output of ls may have unwanted effects.


Removed deprecated options, thanks TechZilla

  • 3
    Your first point is incorrect, unless you meant it's default respective to the -i option, but those 'classic' options have been deprecated. For example to use just one option/line, the new POSIX man page recommends -L1. To call the old behavior of -i, the page recommends the -I'{}' option. – J. M. Becker Feb 18 '13 at 20:44
  • So, its actually about '' instead "" symbols. I guess ' prevents shell evaluation of ``. See my edits. – majkinetor Feb 18 '13 at 20:52
  • @TechZilla: thanks for the corrections. @majkinetor: yes and no, you need to delay the evaluation, but I don't think you can use backticks (`). – Thor Feb 18 '13 at 21:00
  • 1
    @majkinetor: ah, I see what you mean now. To rename files in this manner I would rather use rename, e.g.: rename 's/\.sh//' *.sh. Try first with dry-run (-n). – Thor Feb 18 '13 at 21:16
  • 1
    @majkinetor: rename does work great, and fairly simple, but remember it's very distribution specific. RHEL and Debian based distributions provide different rename commands, so one must keep that in mind when creating cross-distro scripts. – J. M. Becker Feb 28 '13 at 16:01

I'm unsure about your question, are you actually asking why your first line doesn't work? Or are you looking for a proper method to rename all the .sh files?

Assuming it's the cleanest method, I prefer to prepare command options before xargs. For removing a .sh file extension, I often consider this approach,

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv

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.