1

I wanted to move 1000 files in a directory to another dir. I can do it if I'm in the original dir but if I try this

mv $(ls /home/jeremy/source|tail -1000) /home/jeremy/dest

from elsewhere, the path gets stripped and so I would need to append the path somehow. I find the $ convenient and wanted to avoid xargs as it seems tricky.

terdon
  • 242,166

2 Answers2

1

If your command would work if the commandline would not become too long then you can use (the tricky) xargs this way:

 ls /home/jeremy/source | tail -1000 | xargs mv -t /home/jeremy/dest

This assumes there are no newlines and other special characters in the filenames (or the path) otherwise tail will not work properly and xargs will get split filenames (as it works on lines unless you specify xargs -0).

The -t argument to mv allows you to specify the target directory before the file arguments that need to be copied to the target.

Anthon
  • 79,293
1

With recent[1] versions of GNU findutils and coreutils:

find /home/jeremy/source -print0 | 
    tail -z -n 1000 | 
    xargs -0 -r mv -t /home/jeremy/dest/

The -print0, -z, and -0 options tell all three tools to use a NUL character as the filename/record separator. This makes it safe to use this pipeline with filenames containing ANY character.

If your version of tail (or head) doesn't support the -z option, you can use newline as the filename delimiter (which will be safe for ANY filename except those containing newlines):

find /home/jeremy/source | 
    tail -n 1000 | 
    xargs -r -d '\n' mv -t /home/jeremy/dest/

BTW, xargs isn't tricky at all. It's a fairly simple command that takes data from stdin and uses it to run programs (with the data from stdin used as arguments on that program's command-line). It's a useful tool that's well worth the small amount of time it takes to learn.

More importantly, unlike $(ls ...) and similar, using xargs avoids most (all if you use NUL as separator) problems with spaces, shell globbing characters (wildcards etc), and other annoying characters (which are perfectly legitimate characters in filenames, so a well-written script will take care not to be broken by them).


[1] I don't exactly know when head and tail got -z options, but over the last few years, many of the GNU tools (including sort) have gained the ability to use NUL as the input record separator. Before that, it was only a handful of tools like find and xargs.

This is extremely useful, as you can now use these -z or -Z or -0 etc options to build long, complicated pipelines without ever having to lose that useful NUL-separation.

cas
  • 78,579