Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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`'
share|improve this question
add comment

2 Answers 2

up vote 4 down vote accepted

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

share|improve this answer
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. –  TechZilla 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
    
@thor: +1, You're a class act, don't see that enough around the SE's. –  TechZilla Feb 18 '13 at 21:04
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
show 2 more comments

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
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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