2

I'm writing a bash script which change spaces to underscores in the names of the files in the current directory. This is the script:

#!/bin/bash


for fil in "$(pwd)"/*; do 
    basefil=$(basename "$fil") #get name of file
    name=${basefil// /_}
    
    if [[ ! -f "$name" ]]; then
        echo "$fil" "$name"
        mv "$fil" "$name"
        
    fi
done

The problem is that I get something like this:

mv: cannot move '/home/gustavolozada/Downloads/prueba' to a subdirectory of itself, 'prueba/prueba'

I only get this with directories. I added the echo "$fil" "$name" to get a little more info and this is what it shows:

/home/gustavolozada/Downloads/prueba prueba

I do not understand what is the problem, because the command is basically:

mv /home/gustavolozada/Downloads/prueba prueba

which to me does not have any problem whatsoever (besides the fact that they are the same file, but I already check if there is a file with that name in the directory with if [[ ! -f "$name" ]]; then

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • `-f` only checks file not directory. Use `-d` for directory. – kaylum Oct 12 '20 at 02:55
  • 1
    Actually, use `-e` to check whether *anything* (directory, file, whatever) exists under the new name before trying to rename to that. You could also use `for fil in "$(pwd)"/*" "*; do` so it'll only try to rename things that actually have spaces in the name. I'd also recommend `mv -i` juuuust in case. – Gordon Davisson Oct 12 '20 at 03:39
  • This question has allready been anwsered in https://stackoverflow.com/questions/11270453/how-to-remove-spaces-from-file-names-in-bulk – Oliver Gaida Oct 12 '20 at 03:58
  • 1
    To answer the specific question of why it's failing (even though there is already an existing answer to the stated goal), the problem is that you aren't excluding cases where there is no change to be made to the filename. If `$name` and `$fil` are the same (after substitution) then you can skip that case, too (whether it's a file or a directory). But additionally, as stated by @kaylum, you should check that the new name doesn't exist as a file or a directory. – B. Morris Oct 12 '20 at 04:26
  • 1
    @OliverGaida That's a Windows / batch file question, not Bash. – Benjamin W. Oct 12 '20 at 04:48
  • @GustavoLozada: Look at the error message: The output you have posted for your _echo_ command can not be related to the error you got, since the error message complained about a directory entry called _prueba_. However, in this case, I would I would not have expected an error message; the `prueba` should simply be renamed to itself (unnecessary, but harmless). Instead of putting spurious `echo` commands into your script, run the whole script with `set -x`, to find where the `prueba/prueba` comes from? – user1934428 Oct 12 '20 at 10:21
  • It fixed when I replaced -f with -e, as @Gordon Davisson said. It also doesn't have any problems if I use `if [[ ! -f "$name" && ! -d "$name" ]]` because I check for files and directories. – Gustavo Lozada Oct 12 '20 at 12:15
  • @B.Morris I thought I was excluding cases where there was no change to be made. `if [[ ! -e "$name" ]]` (and previously `if [[ ! -f "$name" ]]`) here I checked if there was already a file with that name, and only if there wasn't (ie, if `$fil` and `$name` are different) it'll do the change. – Gustavo Lozada Oct 12 '20 at 12:23
  • @user1934428 I apologize for that. The thing was I was getting the same error for two different directories, and I only posted once on the example, but I posted the results from the echo of the other. I already fixed that. Also, I tried to use set -x, but I don't understand what it does exactly. Is it something like a debugger? – Gustavo Lozada Oct 12 '20 at 12:31
  • If you run your program with `bash -x SCRIPTNAME` or put a `set -x` inside the script, you see every command as it is executed. In particular, you see how the variables are expanded. BTW, while I would write the test as `if [[ -d $name ]]` for various reasons, I'm pretty sure that this won't help in this case. – user1934428 Oct 12 '20 at 14:46

1 Answers1

0

Just a bizarre idea for an explanation: Since name in your error case has the value of prueba/prueba, but has been calculated via basename, it should not contain any slashes. Could it be that Downloads/prueba is a symlink?

user1934428
  • 19,864
  • 7
  • 42
  • 87
  • I'm not good with symlinks, in fact, I do not understand what they are exactly, I just know that they have something to do with the icons of programs. I remember when I installed MATLAB a while ago, I made a mistake and because of that, it didn't have a symlink and everytime I wanted to run it, I had to `cd` to it's directory and run it (I eventually fixed it), but that's all I know about them – Gustavo Lozada Oct 12 '20 at 12:40
  • You don't need to be "good at". You just need to check, whether it is one. You could test it as `if [[ -h $name ]]` – user1934428 Oct 12 '20 at 14:48
  • @GustavoLozada : [here](https://www.nixtutor.com/freebsd/understanding-symbolic-links/) is a short and easy-to-read explanation, what symbolic links are. I'm not sure that they really are the culprit. We really need your program trace. – user1934428 Oct 12 '20 at 14:53