0

I've some files and directories within the directory /var/foo/bar/baz. Now, I want to move all of them up into /var/foo/bar, and get rid of baz. Easy, right?

cd /var/foo/bar
mv baz/* .
rmdir baz

(I'm ignoring files beginning with . for the sake of this discussion)

but! What if baz/ contains a non-directory file named baz? I can move it to someplace else, or use a temporary filename, then delete the directory baz, then move it into place. But that's tedious and a lot of commands, too... is there another, customary, simpler/more-elegant way to do thus?

Note:

  • If there are other name clashes, the normal semantics of mv, which is to overwrite (and possibly prompt) are fine. But with baz, it won't do that, it'll just fail.
0
cd /var/foo/bar/baz
for src in *; do
    dest="${src}"
    suffix=0
    while [[ -e ../"${dest}" ]]; do
        dest="${src}.${suffix}"
        suffix=$((suffix+1))
    done
    mv -n "$src" ../"$dest"
done
cd ..
rmdir baz

A rather straightforward solution. Prepare to move a file from the current directory to the parent directory, but if anything already exists with that name, add a suffix with a number. But make sure not to use a number that also somehow already exists for some reason.

The construct [[ -e file ]] will return true if anything called file exists, whether it be a directory, socket, regular file, or whatever else might exist.

  • This isn't failsafe. Maybe I have files with lots of zeros? Unlikely, but possible... also, it's quite a hassle. 12 lines? – einpoklum Apr 3 '18 at 21:03
  • See my own answer... – einpoklum Apr 3 '18 at 21:10
  • I don't understand your complaint about "files with lots of zeros". Nor do I understand what you mean by "not failsafe". If you want to take care of all the nonconflicting files, just use mv -n * .. and deal with the remainder manually. Anything more robust will require some logic to detect and deal with any conflicting files in a way that will not itself conflict. mktemp is not proof to never collide with an existing file (though it is unlikely); adding a numerical suffix will at least preserve the original filename for you. – DopeGhoti Apr 3 '18 at 21:12
  • If literally your only concern was "what if there is a file called baz", then yes, you can check for just that one case. But what about other files or directories that might be in the new files' location? – DopeGhoti Apr 3 '18 at 21:15
  • That was my literal concern, since you often get that when an archive is decompressed into a folder with the same name, but has the same name again as a folder on the inside. Anyway - with this code, I don't get baz/baz moved to baz eventually. And for everything else - I want an overwrite, just like with mv. – einpoklum Apr 3 '18 at 22:15
0

This is too long, but should work:

cd /var/foo/bar
bazbaz_tmp_file=$(mktemp baz/XXXXXXXXXXXXXX)
[[ -e baz/baz ]] && mv baz/baz $bazbaz_tmp_file
mv baz/* .
rmdir baz
mv $(basename $bazbaz_tmp_file) baz

Note: This assumes that we can safely move any other files up from within baz/.

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.