It's never a good idea to use the output of ls
for anything except viewing in a terminal. See Why not parse ls
(and what to do instead)?. Instead, use find
:
find /home/balaji/work/ -type f -printf '%C@\t%p\0' |
sort -z -k1,1 -r -n |
cut -z -f2 |
head -z -n 10 |
xargs -0r echo mv -t /home/balaji/regular_archive/
This requires the GNU versions of find
, sort
, cut
, tail
, and xargs
(or, at least other versions of them that support the -z
option for NUL record separators).
find
uses -printf '%C@\t%p\0'
to list the last-changed timestamps (%C@
, in seconds since the epoch 1970-01-01 00:00:00) and filenames (%p
) of all regular files. The fields are separated by a single tab (\t
), and each record is separated by a NUL character (\0
)
- the output of find is piped into sort to reverse sort (
-r
) the files numerically (-n
) on the first field only (-k 1,1
) -- i.e. by the timestamp.
- sort's output is piped into cut to delete the timestamp field (we no longer need it after we've finished sorting)
- cut's output is piped into
head
to get the first ten entries
- and finally, head's output is piped into
xargs
to run the mv
command. This uses the GNU -t
extension to mv, so that the target directory can be specified before the filenames.
Actually, this runs echo mv
rather than mv
, so it's a dry-run. Get rid of the echo
when you're sure it's going to do what you want.
Note: This will work with any filenames, no matter what weird and annoying characters they might have in them (e.g. spaces, newlines, shell metacharacters, etc). Also, The file
command has many other options which can be used to refine the search criteria.
If you have an old version of GNU coreutils (i.e. < version 8.25), neither cut
nor head
nor tail
will have -z
options. You can use awk
instead. e.g.
find /home/balaji/work/ -type f -printf '%C@\t%p\0' |
sort -z -k1,1 -r -n |
awk -F '\t' 'BEGIN {RS=ORS="\0"}; NR<=10 { $1=""; $0=$0; $1=$1 ; print }' |
xargs -0r echo mv -t /home/balaji/regular_archive/
Alternatively, you could use perl
instead of awk
:
perl -F'\t' -0lane 'if ($. <= 10) {delete $F[0]; print @F}'
$i
and/or$regular_archieve
in themv
statement, so... (2) check the values of$i
and$regular_archieve
to see if they're what you expect, and if not... (3) try to determine why and fix the problem; then, if you're still stuck... (4) edit your question to ask for help based on the additional information. – David Yockey Sep 27 '19 at 11:53echo $i
andecho $regular_archive
into thedo
loop before themv
? – David Yockey Sep 27 '19 at 11:53bash: work: command not found
error followed by several other errors (mostly due to simple syntax errors). You may want to consider testing your code in https://www.shellcheck.net/ Do this while you are writing it, not after finishing your script. Also test each command as you write them down in the script so that you know they do what you'd expect them to do. – Kusalananda Sep 27 '19 at 15:25