7

This question already has an answer here:

I have a list of files, which I would like to move from folder A to folder B, but I do not want to do that by hand. Is there an easier way to loop through the list and move every file which is on that list?

marked as duplicate by don_crissti, Gilles, Stephen Rauch, Jeff Schaller, John WH Smith Jul 12 '17 at 1:46

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • It's close, but the duplicate target is a more complex situation as the list of files to move contains leading whitespace. – roaima Jul 17 '17 at 10:38
2

I assume that you have only file names. This is the simplest way to do that I think:

while IFS= read -r file; do mv -v "dirA/$file" "dirB/$file"; done < listfile.txt
10

You could use rsync to move them, assuming your list of files is one filename per line.

rsync -av --remove-source-files --files-from filelist.txt sourceDir/ targetDir/

If your files are absolute names (i.e. the names begin with /) the sourceDir should be /. Otherwise it should be the root of the relative names.

Example

$ mkdir src dst
touch src/{one,two,three}
$ cat >filelist.txt <<EOF
one
two
EOF

$ ls src
one  three  two
$ ls dst

$ rsync -av --files-from filelist.txt --remove-source-files src/ dst/
building file list ... done
one
two

sent 165 bytes  received 70 bytes  470.00 bytes/sec
total size is 0  speedup is 0.00

$ ls src
three
$ ls dst
one  two
5

If you gave GNU core utilities (or other implementations with these specific features) you can use xargs to build an argument list for mv based on the file list:

cd A
xargs -rd '\n' -- mv -t B -- < file-list.txt

Without GNU utilities you can still use a while-read loop. In Bash that could be:

while IFS= read -r file; do
    mv "A/$file" "B/$file"
done < file-list.txt
3

You can easily solve this in ViM with these 10 simple steps:

  1. Open the long list of filenames in ViM.
  2. Type qa to start recording a macro named "a".
  3. Type y$ to yank (copy) the filename.
  4. Type imv A/ to write "mv A/" in front of the filename, then press Escape.
  5. Type A B/ to write " B/" at the end of the line, then press Escape.
  6. Type pj^ to paste the filename and move to the beginning of the next line.
  7. Press q to stop recording the macro.
  8. Type VG:normal @a to replay the "a" macro until the end of the file.
  9. Type :wq rename.sh to save as a bash script named "rename.sh" and quit.
  10. Then finally, at the bash prompt, type chmod +x rename.sh; ./rename.sh to mark the script as executable and run it.
  • 1
    :%s!\(.*\)!mv "A/\1" "B/"! is equivalent to your steps 2-8. But not as easy to read, I'll grant. – roaima Jul 10 '17 at 23:03
0

Here is a POSIX compliant variant without using loops. Items in file-list.txt are separated by newlines.

cd A ; xargs -I{} -- mv -- {} B < file-list.txt

Obviously this variant does not allow file names containing newlines. Additionally it invokes the mv command for every file individually.

The variant by David Foerster uses GNU extensions of xargs and mv. It will invoke single instance of mv for multiple arguments and will be more efficient for long lists of files. It still does not allow file names containing newlines. To overcome this limitation you can use the -0 option and separate the file names by \0 (NULL) characters.

cd A ; xargs -r0 -- mv -t B -- < file-list.txt
0

cpio is a standard Linux archiver that also includes a pass-though mode that makes a convenient way to copy things.

It takes a list of file on standard input, usually this is usually scripted as the output of the find command, but since you already have a list of files, lets use that.

assuming the filenames in the list are relative

cd A; cpio --format=newc -pduv B < filelist.txt

instructing cpio, given a list of file names on stdin, to pass-through, make directories, unconditionally write over anything already there and print a verification line, targeting directory B. Using the newc format allows more than 65536 inodes, just in case you are dealing with that many

  • You probably want -m in there too, to preserve files' permissions and modification time. It doesn't move the files, though. You could add -l to hard-link them, and then use the same list of files to remove the source files, but that's more than your one-liner. – roaima Jul 11 '17 at 20:47

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