0

I've been using the command line more frequently lately to increase my proficiency. I've created a .txt file containing URLs for libraries that I'd like to download. I batch-downloaded these files using

$ cat downloads.txt | xargs wget

When using the wget command I didn't specify a destination directory. I'd like to move each of the files that I've just downloaded into a directory called "vendor".

For the record, it has occurred to me that if I ran...

$ open .

...I could drag-and-drop these files into the desired directory. But in my opinion that would defeat the purpose of this exercise.

Now that I have the files in my cwd, I'd like to be able to target them and move them into the "vendor" directory.

As a side-question: Is there a useful way to print the most recently created files to STDOUT? Currently, I can grab the filenames from the URLs within downloads.txt pretty simply using the following pipeline and Perl script...

$ cat downloads.txt | perl -n -e 'if (/(?<=\/)([-.a-z]+)$/) { print $1 . "\n" }'

This will produce...

react.js
redux.js
react-dom.js
expect.js

...which is great as these are file that I intended on targeting. I'd like to transform each of these lines into a command within a pipeline that resembles this...

$ mv {./,./vendor/}<filename>

... where <filename> is "react.js" then "redux.js", and so forth.

I figure that I may be able to accomplish this using some combination of xargs, eval, and mv. This is where my bash skills drop-off.

Just to reiterate, I'm aware that the method in which I am approaching this problem is neither simple nor ideal. This is intentionally a convoluted exercise intended to stretch my bash knowledge.

Is there anyone who knows how I can use xargs, eval, and mv to accomplish this goal?

Thank you!

wpcarro
  • 1,528
  • 10
  • 13
  • Also... I realize that my Perl and Regex pipeline could be replaced by the following: `$ cat downloads.txt | xargs basename` – wpcarro Jun 16 '16 at 20:31
  • You could always re-download the files in the correct directory then delete the ones that were in the wrong directory (your CWD): `cat downloads.txt | xargs wget -P /directory/` then `cat downloads | xargs rm` – Hunter McMillen Jun 16 '16 at 20:40
  • 1
    Do you literally mean "vendor"? I don't understand exactly, looks like `mv *.* vendor` could do the job? (provided all downloaded files have a dot .) – Stefan Hegny Jun 16 '16 at 20:41
  • I understand how impractical I'm being, but in this particular scenario I'm imagining that I have already downloaded the files using wget and that window has closed. Now I already have the files in my cwd and I'd like to create a pipeline to mv them to the vendor directory. I believe the `replstring` flag for `xargs` is what I'm looking for although I've never used it before... – wpcarro Jun 16 '16 at 20:43
  • @StefanHegny this directory already has other files and I'd like to only move the files that were recently downloaded. I can target those files using `$ cat downloads.txt | xargs basename` I'm missing the final piece to this pipeline that allows me to execute the mv command... – wpcarro Jun 16 '16 at 20:44
  • @wcarroll `for f in $(cat downloads.txt | xargs); do mv $f /new-directory/$f; done` – Hunter McMillen Jun 16 '16 at 20:44
  • 1
    `cat downloads.txt | xargs -i mv {} vendor` ? – Stefan Hegny Jun 16 '16 at 20:47
  • @HunterMcMillen this works, but I was looking for a pipeline as opposed to a script. Still helpful, however! – wpcarro Jun 16 '16 at 20:49
  • "As a side-question: Is there a useful way to print the most recently created files to STDOUT?" You mean like `ls -t`? The question is what do you mean by most recently? The most recent N files, or the files created since a certain time? In the latter case you want `find` – Keith Tyler Jun 16 '16 at 21:16
  • 1
    Beware [UUoC](https://stackoverflow.com/questions/11710552/useless-use-of-cat/) — Useless Use of `cat`. – Jonathan Leffler Jun 17 '16 at 06:31

1 Answers1

0
 xargs -l -a downloads.txt basename | xargs -i mv {}  ./vendor

How this works: The first instance of xargs reads the file names from downloads.txt and calls basename for each of these file names individually (alternatively, you could use basename -a). These basenames are then piped to another instance of xargs, which uses the arguments to call mv, replacing the string {} with the current argument.

mv $(basename -a $(<downloads.txt)) ./vendor

How this works: Since you want to move all the files into the same directory, you can use a single call to mv. The command substitution ("backticks") inserts the output of the command basename -a, which, in turn, reads its arguments from the file.

Michael Vehrs
  • 3,293
  • 11
  • 10