7

As the title says, can I move a file relative to its current position?

Let's assume I am in the root directory, with the following file structure:

...
├──home
   └──user
      ├──Documents
      └──Downloads
         └──foo.bar
...

I want to move foo.bar from Downloads to Documents. You could do mv /home/user/Downloads/foo.bar /home/user/Documents/, but when the directory structure is a bit deeper it is annoying to have to write the nearly same path again.

Is there some way to say, for example:

mv /home/user/Downloads/foo.bar (whatever operator)/../Documents/.

so that the file gets moved relative to its position, one directory up, and into Documents?

1
  • "but when the structure is a bit deeper it is annoying to write the nearly same path again" - Copy/paste is your friend.
    – Vikki
    Mar 20, 2022 at 9:56

3 Answers 3

10

With brace expansion

echo mv /home/user/Downloads/{foo.bar,../Documents/}

(remove echo if the result looks good).

Note this generates /home/user/Downloads/../Documents/ as the target path. I deliberately used the string you chose when introducing your "whatever operator": ../Documents/. But if Downloads is a symlink then /home/user/Downloads/../ may resolve to something other than /home/user/; in such case /home/user/Downloads/../Documents/ won't be equivalent to /home/user/Documents/

(Trivia: cd /home/user/Downloads/../Documents/ may be equivalent to cd /home/user/Documents/. This does not mean mv will see the paths as equivalent. Compare this answer.)

Usually (or if the symlink could interfere) you would simply use /home/user/Documents/ as the target (and you in fact did). This path does not depend on Downloads being a symlink or not. For this reason you may prefer the following brace expansion:

echo mv /home/user/{Downloads/foo.bar,Documents/}

Its form does not emphasize the "relative" aspect (while ../ in our first command does, I guess), still it saves you typing /home/user/ again.

Brace expansion is not specified by POSIX. It works in Bash and in few other shells, but not in pure sh.


After cd

You can simply mv foo.bar ../Documents/ if you cd /home/user/Downloads/ first. Do it in a subshell and the current working directory of the main shell will not be affected:

(cd /home/user/Downloads/ && mv foo.bar ../Documents/)

Notes:

  • Thanks to && if cd fails for whatever reason (e.g. a typo in the path) then mv won't run.
  • Again, if Downloads is a symlink then ../Documents/ may be different than /home/user/Documents/.
2

You can reference your home directory with $HOME or with ~.

Example:

~/Downloads is the same as /home/user/Downloads.

You can also use . to reference the current working directory and .. to reference the parent directory.

Example:

$ pwd     
/home/mashuptwice/test
$ cd ..        
$ pwd
/home/mashuptwice

If you need to reference a directory more often in a shell session, you can also save it into a variable.

Example:

$ dl="$HOME/Downloads"                                                                                                                                                                                     
$ echo "$dl"
/home/mashuptwice/Downloads
$ cd "$dl"
$ pwd
/home/mashuptwice/Downloads
1

Another method would be using dirname to get the directory part of the path

file=/here/is/a/file
echo mv "$file" "$(dirname "$file")/newfile"

result:

mv /here/is/a/file /here/is/a/newfile
2
  • 1
    i think that should be mv "$file" "$(dirname "$file")/newfile" otherwise it won't work if the file is a descendant of a folder with spaces in its name; eg this works with /foo_bar/file but it doesn't work with /foo bar/file (also fwiw it's not uncommon that bash scripts fail on files/folders with spaces in its name)
    – hanshenrik
    Mar 20, 2022 at 6:15
  • Yes. It would have worked for the question, but in general quotes are always an good idea. For something I type interactively I usually have an idea if I need them or not, but if you're unsure use them.
    – allo
    Mar 21, 2022 at 9:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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