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?

Vikki
  • 289
T1M
  • 85

3 Answers3

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
mashuptwice
  • 3,395
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
allo
  • 1,248