3

This question already has an answer here:

I have a directory with over 400 images. Most of them are corrupt. I identified the good ones. They are listed in a text file (there're 100+ of them). How can I move them all at once to another directory on BASH?

marked as duplicate by muru, Stephen Rauch, user259412, G-Man, αғsнιη Nov 6 '17 at 5:55

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.

3

There are several ways to do this that come to mind immediately:

  1. Using a while-loop
  2. Using xargs
  3. Using rsync

Suppose the file names are listed (one per line) in files.txt and we want to move them from the subdirectory source/ to the subdirectory target.

The while-loop could look something like this:

while read filename; do mv source/${filename} target/; done < files.txt

The xargs command could look something like this:

cat files.txt | xargs -n 1 -d'\n' -I {} mv source/{} target/

And the rsync command could look something like this:

rsync -av --remove-source-files --files-from=files.txt source/ target/

It might be worthwhile to create a sandbox to experiment with and test out each approach, e.g.:

# Create a sandbox directory
mkdir -p /tmp/sandbox

# Create file containing the list of filenames to be moved
for filename in file{001..100}.dat; do basename ${filename}; done >> /tmp/sandbox/files.txt

# Create a source directory (to move files from)
mkdir -p /tmp/sandbox/source

# Populate the source directory (with 100 empty files)
touch /tmp/sandbox/source/file{001..100}.dat

# Create a target directory (to move files to)
mkdir -p /tmp/sandbox/target

# Move the files from the source directory to the target directory
rsync -av --remove-source-files --files-from=/tmp/sandbox/files.txt /tmp/sandbox/source/ /tmp/sandbox/target/
  • The first mkdir -p /tmp/sandboc is redundant. – fpmurphy Nov 6 '17 at 0:18
  • @fpmurphy1 That's true, but I wanted that line there mostly for the comment and the logical flow of the presentation. Anyway, I just did some reformatting and now it should no longer be redundant. Thank you for the feedback. – igal Nov 6 '17 at 0:23
  • I tried the while loop and now, the whole directory is gone... The command was while read list; do mv ./${filename} OK/; done < list – Weylyn Savan Nov 6 '17 at 19:31
  • @WeylynSavan Maybe there was a miscommunication? There was no mention in your question of where the files were located, e.g. you made no mention of this "OK/" directory. I also used generic directory names and relative paths in that snippet, so you would have had to run the command with the correct paths and (if you used relative paths) from the right working directory. – igal Nov 6 '17 at 19:43
  • @igal Sorry, I mistyped my comment (and can't edit it anymore). I was outside the working directory. The work dir was named ERROR, it contained the images, the list, and the OK directory. The actual command was while read ERROR/list; do mv ERROR/${filename} ERROR/OK/; done < ERROR/list The first command was obviously not working (why I posted it is a mystery). – Weylyn Savan Nov 6 '17 at 20:34
3

Fast solution with GNU parallel:

Let's say the "good" image filenames are listed in file good_img.txt and the destination folder is named good_images.

cat good_img.txt | parallel -m -j0 --no-notice mv {} good_images 
  • -m - insert as many arguments as the command line length permits. If multiple jobs are being run in parallel: distribute the arguments evenly among the jobs

  • -j N - number of jobslots. Run up to N jobs in parallel. 0 means as many as possible. Default is 100% which will run one job per CPU core.

  • Consider running parallel --bibtex once. – Ole Tange Nov 6 '17 at 9:11
  • @OleTange, it's good, except that annoying prompt Type: 'will cite' and press enter – RomanPerekhrest Nov 6 '17 at 9:53
1

If there is one file name per line:

xargs -d \\n echo mv -t /target/directory
1

While you requested a bash solution, you may have really meant a command-line-based solution. Others have provided using a variety of command-line tools. Here is a solution that uses a bash builtin (readarray / mapfile) to read the contents of the text file in order to then pass those filenames on to the mv command:

Setup

$ touch {a..z}.jpg "bad one.jpg" "good one.jpg"
$ mkdir good
$ cat saveus
j.jpg
good one.jpg
z.jpg

Preparation

$ readarray -t < saveus.txt
$ declare -p MAPFILE
declare -a MAPFILE='([0]="j.jpg" [1]="good one.jpg" [2]="z.jpg")'

Do it

$ mv -- "${MAPFILE[@]}" good/

Confirmation

$ ls -1 good/
good one.jpg
j.jpg
z.jpg
$ ls "good one.jpg" j.jpg z.jpg
ls: cannot access good one.jpg: No such file or directory
ls: cannot access j.jpg: No such file or directory
ls: cannot access z.jpg: No such file or directory

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