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 tried to remove apostrophe from all files' names in the directory.

for i in *; do mv $i `echo $i | tr -d "'"`; done

After executing this command nothing is renamed.

Do you know what's wrong here?

share|improve this question
    
What error message do you see? Do the names also contain spaces? –  Mikel May 6 '12 at 14:39
    
@Mikel There wasn't error message. Yes, the names contained spaces too. –  xralf May 6 '12 at 14:42

3 Answers 3

up vote 5 down vote accepted

You could try something like this (bash):

shopt -s nullglob
for i in *\'* ; do mv -v "$i" "${i/\'/}" ; done

This uses shell string replacement. You probably don't want to glob files that don't have ' in them since the mv would fail. Without the nullglob option, the glob pattern itself would be passed to mv if there are no matching files.

share|improve this answer

Always put double quotes around variable substitutions $foo and command substitutions $(foo) (unless you know why you need to leave them out and why it's ok to do so).

for i in *; do mv "$i" "$(echo "$i" | tr -d "'")"; done

This will mostly work, with a few restrictions:

  • You'll get bad behavior or errors if a file name begins with -, because mv will interpret it as an option.
  • This does not affect files whose name begins with ..
  • With some setups, this will mangle backslashes in the echo command.
  • Newlines at the end of the name are lost.

In ksh93, bash and zsh, you can write this with less hassle using the ${VARIABLE//PATTERN/REPLACEMENT} construct. Adding -- to mv takes care of file names beginning with -. If you have file names beginning with ., add .* or .[^.]* ..?* after * as needed.

for i in *; do mv -- "$i" "${i//\'/}"; done

In zsh, you can use zmv:

zmv '(*)' "\${1//\\'/}"

Under Debian, Ubuntu and other derivatives, you can use the rename Perl script.

rename "s/'//g" *
share|improve this answer

I assume your problem is the file also had spaces in its name. I can't reproduce your error without it.

$ touch "file" "user's file"
$ for i in *; do mv $i `echo $i | tr -d "'"`; done
mv: `file1' and `file1' are the same file
mv: target `file' is not a directory

So the reason it's failing is the second message: target 'file' is not a directory.

When your for loop sees a file with a space, it runs this:

mv user's file users file

So it thinks you're specifying three files (user's, file, and users), and a directory to move those files into (file).

Proper quoting of both should solve your immediate problem

$ for i in ./*; do mv "$i" "$(echo "$i" | tr -d "'")"; done
share|improve this answer
    
Thank you for explanation. This looks like my bug. –  xralf May 6 '12 at 16:51
2  
@xralf Note that there were still missing quotes in Mikel's last snippet, that would mangle multiple spaces and wildcards in file names. –  Gilles May 7 '12 at 1:51
2  
I added ./* in my edit. This prevents file names like -option from being misinterpreted. –  jw013 May 7 '12 at 5:59

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.