I'm having trouble with moving files in a bash script. I've been trying different solutions that I've found here, on the same problem, but can't find anything that works..

my last attempt was adding shopt -s dotglob nullglob but that didn't solve anything..

In this test,


mv -v "$jdir0/*" "$jdir0/subs/" &>> $debuglog

.. and I get:

mv: cannot stat '/media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/*': No such file or directory

but, yes, there are!

drwxrwx--- 1 root vboxsf   4096 Aug 22 07:06  ../
-rwxrwx--- 1 root vboxsf      0 Aug 21 17:19 'kallee.(222)..nnn.srt'*
-rwxrwx--- 1 root vboxsf 159363 Aug 21 17:26 'movie.test(2929).ismim.mp4'*
drwxrwx--- 1 root vboxsf      0 Aug 22 07:06  subs/

(the reason the names are really strange is that I before this function is testing to remove invalid chars)

update: Apparently I got intermittent errors, and I've finally after days traced it back to server issue (where the files where stored). Apparently these errors occurred if the server wasn't finished with the save/name change, and the script asked it to do something new. For example renaming file A to B, and then asking it to rename B to C BEFORE the server had executed the first request, which resulted in that the server said: B don't exist, which of course caused an error code.

  • yes, the $ there isn't there in the script, it was only a way to "explain", but I'll update the question..
    – JoBe
    Aug 22 '20 at 6:28
  • Didn't you ask this before? [Move files with wildcard? ](unix.stackexchange.com/q/604983/170373)
    – ilkkachu
    Aug 22 '20 at 19:42
  • @ilkkachu omg, I had asked this.. sorry forgot it (see my profile).. I was so up in it because sometimes it worked and sometimes it didn't work, so I thought I made mistakes, when it actually was a strange server issue (see the updated question)
    – JoBe
    Aug 22 '20 at 19:52

* is a glob operator of the shell. It needs to be left unquoted to be recognised as such. When quoted, /media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/* is passed literally to mv and mv tries to move that file called *, and there's no such file.

So you need:

mv -v -- "$jdir0"/* "$jdir0/subs/" >> "$debuglog" 2>&1

For the shell to expand "$jdir0"/* into the list of matching files before calling mv.

You do not want nullglob here as that would mean that in the absence of files matching that "$jdir0"/* pattern, mv would be invoked with just -v, -- and media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/subs/ causing a confusing syntax error by mv.

failglob to abort command when the globs don't match may be a better option in that case, though note that bash aborts in inconsistent ways in that case depending on the context the command is invoked in, which makes that option tricky to use in scripts.

dotglob is to allow globs to match hidden files.

Now, note that globs match files regardless of their type¹, so that * above will also match subs. If subs is a symlink to a directory, mv will happily move that subs symlink into that directory, causing all subsequent moves to fail as the subs target directory is now gone. If subs is a plain subdirectory, mv will likely complain that it can't move a directory into itself.

So you may want to write it instead:

shopt -s extglob
mv -v -- "$jdir0"/!(subs) "$jdir0/subs/" >> "$debuglog" 2>&1

Where !(pattern) is the ksh extended glob operator that matches on any filename that does not match pattern, so here moving any file but subs.

Also note that in the bash shell, parameter expansions also need to be quoted when in targets of redirections even in non-interactive shell instances (except when bash is in POSIX mode).

¹ unless you use zsh instead of bash and its glob qualifiers such as *(.) to move only regular files

  • @JoBe, same, but standard sh syntax and more explicit (&>> file is a bash-specific operator to redirect both fds 1 and 2 in append mode to file, similar to csh/zsh's >>&). Aug 22 '20 at 6:20
  • getting error with your code: mv: cannot move '/media/sf_Mediaserver3/test22/abbamax.(8th.copy)..kansas.(1999)/kallee.(222)..nnn.srt' to '/media/sf_Mediaserver3/test22/abbamax.(8th.copy)..kansas.(1999)/subs/kallee.(222)..nnn.srt': Not a directory mv: cannot move '/media/sf_Mediaserver3/test22/abbamax.(8th.copy)..kansas.(1999)/movie.test(2929).ismim.mp4' to '/media/sf_Mediaserver3/test22/abbamax.(8th.copy)..kansas.(1999)/subs/movie.test(2929).ismim.mp4': Not a directory
    – JoBe
    Aug 22 '20 at 6:22
  • @JoBe, that would be the error you get when subs is not a directory. I'd guess you have made several attempts, one of which has moved subs elsewhere and one of which renamed a file to subs. Check the contents of your directory again. Aug 22 '20 at 6:27
  • nope, the subs directory is there, it creates it (and checks if it exists) just before attempting to move the files...
    – JoBe
    Aug 22 '20 at 6:31
  • @JoBe Try and add a set -o xtrace at the beginning of your script to see what is being executed. Aug 22 '20 at 6:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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