Move only the last 8 files in a directory to another directory
You can use for
, which loops over the files in an ordered way, and allows us to avoid parsing the output of find
or ls
, to avoid issues with spaces and other special characters in filenames. Many thanks to @muru for improving this :)
i=0; j=$(stat ~/Documents/* --printf "%i\n" | wc -l); for k in ~/Documents/*; do if (( (j - ++i) < 8 )); then echo mv -v "$k" ~/AnotherDirectory; fi; done
Test it first with echo
, then remove echo
to actually move the files.
As a script:
#!/bin/bash
i=0
j=$(stat ~/Documents/* --printf "%i\n" | wc -l )
for k in ~/Documents/*; do
if (( (j - ++i) < 8 )); then
echo mv -v -- "$k" ~/AnotherDirectory
fi
done
again, remove echo
after testing to move the files for real
Explanation
-
i=0
telling the shell to start iterating at 0 -
j=$(stat ~/Documents/* --printf "%i\n" | wc -l )
this is setting the variablej
to an integer equal to the total number of files in the directory. Thanks to Serg's answer to my own question on how to count files reliably no matter what characters their names contain -
do if (( (j - ++i) < 8 ))
for each iteration of the loop, test whether the outcome ofj
minus the number of times the loop has been run is less than 8 and if it is then -
mv -v -- "$k" ~/AnotherDirectory
move the file to the new directory
You can do things like this using command substitution. In Bash:
mv $(ls -d [sort options] source/* | tail -n8) destination
The $(command)
will run whatever is enclosed in it and substitute the text output into the outer command. That ls
command will print the path to each file in the source directory sorted according the the flags you specify, one per line, so tail
can just take the last few. Thus the above would expand to
mv source/file1 source/file2 source/file3 ... source/file8 destination
You can just run ls -d [sort options] source/* | tail -n8
to see what files it will copy.
Depending on how you're ordering the output of ls
and the file naming, you may be able to do what you're looking for more simply just using some variant of mv source/name_* destination
to copy everything starting with "name_" to the destination directory.
EDIT: The above breaks when there are spaces in the file names. A more complicated alternative that addresses this would be
ls -d1 [sort options] source/* | tail -n8 | tr '\n' '\0' | xargs --null mv -t destination
though it still makes use of parsing ls
output to get sorting in any order that isn't alphabetical.
similar to t-mager's suggestion, you can use ls sort options and grab the last 8 files into a list and these are your files:
1 10 2 3 4 5 6 7 8 9
use the following command:for n in `ls|tail -8`; do mv $n ~/temp; done