Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Is there a clever way to do copy and move operations or a command to duplicate a file, without having to do a cd, then mv after, at the same folder?

For example, I have to run the following:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

Note that the directory to where I'm moving the file is the same, but I have to put the whole path again and sometimes it gets annoying. I'm curious to know if there's another way to do that without having to put the whole path again, because the operation would be done in the same path.

share|improve this question
9  
I can't believe this has so many upvotes. It's a duplicate unix.stackexchange.com/questions/35782/… and unix.stackexchange.com/questions/66889/… –  user13107 May 17 '13 at 16:28
13  
@user13107 There are many ways to ask a question, including different wording. And if you don't know that the answer is called "brace expansion", you might not be able to find it right away. –  slhck May 17 '13 at 16:37
1  
@user13107 they are on a different site so not duplicates –  Mark May 18 '13 at 7:13
1  
Mark, Thanks, I didn't know that rule about duplicates. @slhck Yes. I understand. I was just frustrated because my question on Unix.SE got closed as duplicate and this one got so popular. –  user13107 May 18 '13 at 8:24
2  
@user13107, that's what you get for posting on the right site –  Samuel Edwin Ward May 18 '13 at 14:08
add comment

6 Answers 6

up vote 122 down vote accepted

Simply use brace expansion:

mv /folder1/folder2/folder3/{file.txt,file-2013.txt}

This is equivalent to writing:

mv /folder1/folder2/folder3/file.txt /folder1/folder2/folder3/file-2013.txt

Brace expansion lets you supply more arguments, of course. You can even pass ranges to it, e.g. to create a couple of test folders, you can run mkdir test_{a..z}, and starting with Bash 4, you can create zero-padded sequences as well, as in touch foo{0001..3}, which creates foo0001, foo0002 and foo0003. The Bash Hackers Wiki has an article with a couple of examples for you.

If you have to use two different commands, use a subshell and cd there first, as in @Ignacio's answer.

share|improve this answer
4  
I didn't know about the brace expansion, thank you! –  Valter Henrique May 17 '13 at 12:49
    
I tried and it seems not to work: meniac ~: mv /tmp/f1/f2/f3/f4/f5/f6/{file.txt, file2.txt} mv: cannot stat ``/tmp/f1/f2/f3/f4/f5/f6/{file.txt,': No such file or directory –  Valter Henrique May 17 '13 at 12:54
4  
Are you sure you're using Bash, as in /bin/bash, and you're not in a script that has /bin/sh in the shebang or some other shell that doesn't support brace expansion? If you run set, do your SHELLOPTS contain braceexpand? –  slhck May 17 '13 at 12:57
22  
Note that there should be no space between file.txt, and file2.txt. –  slhck May 17 '13 at 13:15
8  
You can make it even shorter, to prevent typos in the part that does not change: mv /folder1/folder2/folder3/file{,-2013}.txt –  Jan Fabry May 18 '13 at 21:19
show 2 more comments

Run the operation in a subshell.

( cd /folder1/folder2/folder3 && mv file.txt file-2013.txt )

The change of working directory won't be propagated to the parent shell.

share|improve this answer
    
I got it Ignacio, thank you for your answer mate. –  Valter Henrique May 17 '13 at 12:49
11  
+1: I like that one, more portable across shells than the brace-expansion trick (which is neat, but less portable) –  Olivier Dulac May 17 '13 at 16:51
    
@Olivier, what makes you think brace expansion is not portable? Which shell do you have in mind that does not support it? –  alexis May 17 '13 at 17:54
5  
@alexis Brace expansion is not specified by POSIX so is non portable "by design". ash, dash, ksh88 not to mention the old bourne shell are example of shells not supporting it. –  jlliagre May 17 '13 at 21:10
2  
@Kaz I care about portability of shell commands and the fact they are interactive or not doesn't matter. Of course, you are certainly free not to care about this but please accept that people think otherwise. The fact you always use bash or a shell that support barce-expansion doesn't means that's everyone's case. –  jlliagre May 20 '13 at 6:03
show 3 more comments

If you want clever, here's bash history expansion

mv /folder1/folder2/folder3/file.txt !#:1:h/file-2013.txt

I wouldn't use this myself since I find it impossible to memorize. I do occassionally use the vim equivalent, but have to look it up almost every time.

share|improve this answer
    
Nice one… figured there was a way to do that, but never cared to look up the manual. –  slhck May 17 '13 at 13:27
add comment

You can set a variable. Of course this has the side-effect of leaving the variables around.

D=/folder1/folder2/folder3; mv $D/file.txt $D/file-2013.txt
share|improve this answer
    
And, of course, you can avoid the side-effect of leaving the variable(s) around by putting the entire command line into a subshell: (D="/folder1/folder2/folder3"; mv "$D"/file.txt "$D"/file-2013.txt), or simply by adding an unset command at the end. (I added quotes as a “best practice”; if you get in the habit of always using quotes, you won’t have to stop and scratch your head when a pathname that contains special characters comes along.) –  Scott May 24 '13 at 20:27
    
@Scott if you're going to use a subshell to eliminate side-effects, it's easier to do a cd than to set a variable. Not a lot easier, I admit. –  Isaac Rabinovitch May 25 '13 at 22:59
add comment

I like the other solutions, but here is another, implemented as a script with bash arrays, pushd, popd:

#!/bin/bash
set -e
# from http://stackoverflow.com/a/246128/178651
script_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# paths relative to the script
relative_paths=( \
path1 \
path2 \
path3 \
path4
)

for relative_path in "${relative_paths[@]}"
do
  pushd "$script_path/$relative_path" > /dev/null 2>&1
  pwd
  mv filename1 filename2
  # could do other stuff in this directory...
  popd > /dev/null 2>&1
done

pushd "$script_path" > /dev/null 2>&1
# could do other stuff in same directory as script...
popd > /dev/null 2>&1
share|improve this answer
add comment

Slhck directly answers the question in the simplest possible way, but Valter also likes the autopop answer, so here's one that's along the same lines;

pushd /folder1/folder2/folder3/; mv file.txt file-2013.txt; popd
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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