ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Distribution: slack current with 2.6.16.18 (still off the hook)
Posts: 284
Rep:
Bash, renaming files won't work
Hi, I'm trying to rename a lot of files getting rid of the space on the names. For that purpose I wrote this very simple bash script, but for some reason is not working.
Code:
for i in "$(ls)"
do
j=$(echo "$i" | sed 's/\ /_/g')
mv "$i" "$j"
done
But what I get in return for each line is just one long file name with all the file names concatenated.
I've tried with echo -e "$i" as well with no results.
This has to be something really simple that I'm missing but I just can't see it.
You're working along the right idea, but using `ls` for this is not a great idea. Go to LQ's Search Engine and enter:
Code:
rename filename spaces
into the keyword search field; select "Search Entire Posts" from the dropdown gadget below that text field, and click "Search Now" -- you will find many examples of how to do just what you're doing here. Adjust your search keywords as necessary, but I think you'll find the answer on one of the pages returned.
Actually the reason why you get all file names concatenated together is that double quotes prevent field splitting (that is a string embedded in double quotes is seen as a single string, despite the presence of blank spaces). This means the loop is cycled only once and the loop variable get the value:
Code:
file one file two file three
Anyway, since you have file names with blank spaces, you have to find a way to prevent file names splitting in two or more pieces. One of them could be:
Code:
while read file
do
echo "$file"
done < <(ls *\ *)
Here the "read" statement assigns every line of the input to the variable "file". Just use double quotes around "$file" inside the code block and the trick is done.
An even more simple solution is mass renaming using the rename command. However, there are two versions of rename: one coming from util-linux for which you can simply do:
Code:
rename ' ' '_' *\ *
and another (coming from perl) which uses perl expressions, for which the syntax would be:
Code:
rename 's/ /_/g' *\ *
Looking at the manual page of rename, you can easily find out which version is installed on your system.
Anither solution (slightly tested!) is to use plain file name expansion
Code:
for file in *
do
[[ $file != ${file// } ]] && /usr/bin/mv "$file" "${file// }"
done
Hi catkin. Your solution works, except for the substitution of blank spaces with underscores. Hence, the substring replacement should be
Code:
"${file// /_}"
Surprisingly it works even if I do (but maybe this is not robust)
Code:
for file in *\ *
do
mv "$file" "${file// /_}"
done
which is almost the same as yours, except the file list contains only names with spaces. But shouldn't it split each name in the file list into pieces?!
But shouldn't it split each name in the file list into pieces?!
The closest to an explanation of how it does behave is here where in step 4 Bash "# Performs the various shell expansions (see Shell Expansions), breaking the expanded tokens into lists of filenames (see Filename Expansion) and commands and arguments". Filename Expansion comes after breaking the command up into IFS-character-separated words and a single glob can be expanded into several words, each of which may contain IFS-characters ...
EDIT:
The above is not accurate. Where I wrote "after breaking the command up into IFS-character-separated words" it should have been "after breaking the command up into metacharacter-character-separated words where a metacharacter is one of:
Filename Expansion comes after breaking the command up into IFS-character-separated words and a single glob can be expanded into several words, each of which may contain IFS-characters ...
import os
os.chdir("/mypath")
for files in os.listdir("."):
if os.path.isfile(files) and " " in files:
newfile=files.replace(" ","_")
os.rename(files,newfile)
$ ls -1
file one.txt
file three.txt
file two.txt
file1.txt
file2.txt
file3.txt
$ find . -name "*\ *" > x
$ cp x y
$ sed -i 's/.*/"&"/' x
$ tr " " "_" < y > z
$ paste x z | sed 's/^/mv /' > s; sh s
$ ls -1
file_one.txt
file_three.txt
file_two.txt
file1.txt
file2.txt
file3.txt
s
x
y
z
$
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.