LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   Bulk file rename not working as expected (https://www.linuxquestions.org/questions/linux-general-1/bulk-file-rename-not-working-as-expected-888378/)

mago 06-25-2011 08:13 PM

Bulk file rename not working as expected
 
Hello everyone,

Here comes a question that most likely than not is very simple, but I think I'm blocked and I don't see it.

Y want to rename a bunch of files and directories to remove the space on the names, easy enough right?
Code:

for source in $(find ./); do target=$(echo "$source"|sed -e 's/ /_/g'); mv -f "$source" $target; done
Well, I thought that should have work but the problem is that $source comes up broken, when I run it with echo instead of mv I get the echo with broken names.
Code:

In this case "$source"="This is the file I want to rename"

$ echo "$source"
This
is
the
file
I
want
to
rename
$

Any suggestions?
Running Fedorea core 14
Bash version 4.1.7
gnu sed version 4.2.1


Thank you.

allez 06-25-2011 11:53 PM

Try this way:
Code:

find | while read _source; do mv "${_source}" "${_source// /_}"; done

mago 06-26-2011 01:08 AM

Thank you, that did the trick.

Seems to be that echo cannot carried the spaces, it changes them with \n even before the substitution.

Thank you allez!

David the H. 06-26-2011 03:30 AM

A for loop simply breaks the input (the part after "in", or the positional parameters) up into separate "words" and processes them individually. If you want to take "per line" input from an external command or file then you should use a while+read loop instead.

Also, while the above suggestion works in this situation, using a pipe to feed the loop is not the best option because the loop will run in a subshell and any variables set inside it will be lost when the loop terminates. This is the recommended way:
Code:

while read _source; do
    mv "${_source}" "${_source// /_}"
done < <(find ./)

See here: http://mywiki.wooledge.org/BashFAQ/024

(Edit: That find command will also include directories in the input, so you may have problems if you're trying to do this recursively, as it will rename the directory before the files inside it, and so subsequent mv commands will fail. You should use the -type f option to limit it to files only, then run it again with -type d to process the directories ).

Incidentally, if all you want to do is grab files from the current directory, then you don't need find at all, just globbing, and you can go back to using a for loop (globbing expansion takes place after word breaking, so filenames won't be broken up).

Code:

for source in ./* ; do
    mv "${_source}" "${_source// /_}"
done

Finally, instead of writing your own scripts, you might consider using one of the many useful bulk renaming programs that are already out there. I like qmv from renameutils, for example, and the perl-based rename utility that comes with some distros. So I just do this to remove spaces from filenames:

Code:

rename -v 's/ /_/g' ./*
Use your google-fu for more.
http://www.google.com/search?&q=linux+bulk+rename


All times are GMT -5. The time now is 09:41 PM.