0

Source path:

/var/log/

Here I have 4 folders named ad1nrld,ad2nrld,icp1rmnrl,icp2rmnrl

I can move all the files to the other destination named /home/spsy/logs_bkp. But I want to keep latest 5 files in each folders (ad1nrld,ad2nrld,icp1rmnrl,icp2rmnrl) of this /var/log path and rest will be moved to /home/spsy/logs_bkp path.

At source path, /var/log/ad1nrld - Only latest 5 files will be present and rest will be moved to /home/spsy/logs_bkp/ad1nrld path

I have tried the below code for moving the files and they are successfully moved. But I am unable to keep latest 5 files in the respective folders.

for i in `ls -1rt | egrep 'nrld|mnrl'`
do
cd $i
mv *log /home/spsy/logs_bkp/$i
echo "files moved for &i"
cd ..
done

The below part is not working while I am adding the code to keep latest 5 files.

for i in `ls -1rt | egrep 'nrld|mnrl'`
do
cd $i
count_files=`ls -lrt | wc -l`
if [ $count_files -gt 5 ];
then
tomove=$(($count_files-5))
for part in `ls -1rt`
do
if [ $tomove -gt 0 ]
then
mv $part /home/spsy/logs_bkp/$i
tomove=$(($tomove-1))
echo "files moved for &i"
cd ..
fi
done
fi
done
4
  • Modified. It should be Latest 5 files
    – Nainita
    Feb 23 at 21:08
  • 1
    If you move everything to /home/spsy/logs_bkp, how do you deal with duplicate file names?
    – pLumo
    Feb 24 at 7:21
  • My files are generated everyday with unique timestamp. So there is no duplication of files in the same folders.
    – Nainita
    Feb 24 at 7:23
  • I am curious why you would not use logrotate to handle the logs? Feb 24 at 17:15

3 Answers 3

3

zsh is generally available on Solaris unless you installed a stripped down version of it, so you should be able to do:

#! /usr/bin/zsh -
src=/var/log dst=/home/spsy/logs_bkp
dirs=(ad1nrld ad2nrld icp1rmnrl icp2rmnrl)

ret=0
for dir ($dirs) () {
  if (( $# > 5 )) mv -- $@[6,-1] $dst/$dir/ || ret=$?
} $src/$dir/*(N.om)
exit $ret

That uses the om glob qualifier to order the glob expansion (only regular files with the . qualifier) by modification time (from youngest to oldest like ls -t does). Add the D qualifier if you also want to consider hidden files.

That glob expansion is passed to an anonymous function which moves the 6th to last files as long as there are more than 5 in the directory, doing it for each $dir in $dirs.

With ksh or other shells, without glob qualifiers the difficult part is to order the list of files by modification time and restrict to regular files only.

ls -t will sort by modification time, but you can't easily reconstruct the list of files from its output unless you can guarantee file names won't contain newline characters. If you're in such a special case, you can do:

#! /bin/sh -
src=/var/log dst=/home/spsy/logs_bkp
dirs='ad1nrld
ad2nrld
icp1rmnrl
icp2rmnrl'

IFS='
' # split on newline only
set -o noglob # disable globbing so we can use split+glob to split.

ret=0
for dir in $dirs; do # split+glob to split $dirs
  set --
  for file in $(ls -t -- "$src/$dir/"); do # split+glob to split ls output
    [ -f "$file" ] && [ ! -L "$file" ] && set -- "$@" "$src/$dir/$file"
  done
  if [ "$#" -gt 5 ]; then
    shift 5
    mv -- "$@" "$dst/$dir/" || ret="$?"
  fi
done
exit "$ret"
1

Version, that does not rely on parsing ls, but uses find and \0 as line terminator:

(As you're using Solaris, and this uses GNU extensions, this might not be possible for you, but might be useful for others).

dirs=(ad1nrld ad2nrld icp1rmnrl icp2rmnrl)
for dir in "${dirs[@]}"; do
    find "$dir" -maxdepth 1 -type f -printf '%T@\t%p\0' \
      | sort -rnz \
      | tail -z -n+6 \
      | cut -z -f2- \
      | xargs -r0 mv --backup=numbered -t logs_bkp/
done
3
  • Note that find -printf -maxdepth, sort/tail/cut -z, xargs -0, mv -t --backup are all GNU extensions, and the OP mentioned using Solaris. Feb 24 at 7:40
  • I had a feeling, that this would be an issue ... I'll leave a note, but this might be useful for others anyway
    – pLumo
    Feb 24 at 7:42
  • @pLumo Yes, GNU will not work in my Solaris versions (5.8).
    – Nainita
    Feb 24 at 8:55
0

Script is working. I have 4 folders named ad1nrld,ad2nrld,icp1rmnrl,icp2rmnrl in /var/log path. Script will keep latest 5files in the respective folders and rest will be moved to the respective folders of the /home/spsy/logs_bkp path.

This is the code.

cd /var/log
for i in `ls -1rt | egrep 'nrld|mnrl'`
do
cd $i
count_files=`ls -lrt | wc -l`
if [ $count_files -gt 6 ];
then
tomove=$(($count_files-6))
for part in `ls -1rt`
do
if [ $tomove -gt 0 ]
then
mv $part /home/spsy/logs_bkp/$i
tomove=$(($tomove-1))
fi
done
cd ..
fi
done
4
  • See unix.stackexchange.com/questions/68694 (about quoting), and unix.stackexchange.com/questions/128985 (about ls). I'm also wondering why you use ls with egrep in your outer loop when you know the exact names of the directories that you want to loop over?
    – they
    Feb 24 at 7:00
  • You should consider indenting your code blocks to improve readability. Also make sure your variables are always inside double quotes when you use them. Remember to put a #!/bin/sh at the top of the file (first line) to show the system that you've written this script in sh.
    – roaima
    Feb 24 at 7:27
  • This will break if any file name contains spaces. If this can be guaranteed not to happen then you're reasonably safe
    – roaima
    Feb 24 at 7:32
  • Yes..It is guaranteed that file names are stored in a predefined manner and won't change in future. Also Shebang is added in the script as it will be executed from the crontab itself.
    – Nainita
    Feb 24 at 7:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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