Bash – Why doesn’t this xargs command work

bashtext processingxargs

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`;

EDIT:

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

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

Best Answer

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

Notes:

  • 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.

Edit

Removed deprecated options, thanks TechZilla