How to create symlink for latest file only?

Hello,

On Solaris 10, here are entries for logs in httpd.conf

ErrorLog "|/export/apache/apache-2.2.17/bin/rotatelogs -l -f /var/log/apache/error_log.%Y%m%d 86400"

It keeps creating daily logs with below names -

-rw-r--r--   1 root     root     1016747232 Apr  5 23:59 /var/log/apache/error_log.20190405
-rw-r--r--   1 root     root     946721391 Apr  6 23:59 /var/log/apache/error_log.20190406
-rw-r--r--   1 root     root     1092546540 Apr  7 23:59 /var/log/apache/error_log.20190407
-rw-r--r--   1 root     root     1172486303 Apr  8 23:59 /var/log/apache/error_log.20190408
-rw-r--r--   1 root     root     909466871 Apr  9 23:59 /var/log/apache/error_log.20190409
-rw-r--r--   1 root     root     916731172 Apr 10 23:59 /var/log/apache/error_log.20190410
-rw-r--r--   1 root     root     785326845 Apr 11 23:59 /var/log/apache/error_log.20190411
-rw-r--r--   1 root     root     463003111 Apr 12 13:38 /var/log/apache/error_log.20190412

I want to create a symlink 'error_log' and that should point to latest log file. One idea is, to create two cronjobs for 00:00 midnight, something like this

00 00 * * * ln -s /var/log/apache/error_log.20190412 /var/log/apache/error_log
59 00 * * * unlink /var/log/apache/error_log

But how will I tell cron, to pick only latest error_log.xxxxxx ? Is it possible ?

Thanks

1 Like

Fortunately, your file names are "sort friendly". Try

ls  *log.* | sort | tail -1
1 Like

Yes, that can help. How can I pass that name to cronjob ?

Alternatively I thought of passing same syntax as mentioned in logrotate, but that fails

bash-3.2# ls -l /var/log/apache/error_log.%Y%m%d
/var/log/apache/error_log.%Y%m%d: No such file or directory
bash-3.2#

If this can work, I can pass that in cron in similar way

00 00 * * * ln -s /var/log/apache/error_log.%Y%m%d /var/log/apache/error_log
59 00 * * * unlink /var/log/apache/error_log
1 Like

shell uses backticks and $( ) to turn program output into strings.

cd /var/log ; ln -s $(ls  *error_log.* | sort | tail -1) error_log
2 Likes

This worked well. Thanks much

1 Like

I'd not bother with the sort. The output should be lexically ordered anyway, so it's redundant.

In some OS, you might need to add a -f to get it to replace the sym-link, and of course you need permission to write to the directory (which root will have, naturally)

Robin

1 Like

I would also be inclined to use the reverse-sort option to ls , and head instead of tail , thus:

cd /var/log ; ln -s $(ls -r  *error_log.*  | head -1) error_log

Andrew

Yes, and ensure a successful cd :

cd /var/log && ln -s "$(ls -r *error_log.* | head -1)" error_log

BTW ls -r is good here; ls -t would really sort by mtime.

I gave below command in crontab, it executes, but failed with rc-2

13 16 * * * cd /var/log/apache && ln -s $(ls -r *error_log.* | head -1) error_log
14 16 * * * unlink /var/log/apache/error_log

From /var/cron/log -->

>  CMD: cd /var/log/apache && ln -s $(ls -r *error_log.* | head -1) error_log
>  root 16954 c Thu Apr 18 16:09:00 2019
<  root 16954 c Thu Apr 18 16:09:00 2019 rc=2

That is not very surprising. You try to create a symlink at 4:13 pm (which fails because a symlink by that name already exists) and then you remove the symlink at 4:14 pm.

Furthermore, due to occasionally heavy load conditions, there is no guarantee that one cron job scheduled to start at a given time will complete before another job scheduled to run one minute later.

Why not do both in one step (assuming that you aren't really trying to create a symbolic link that has a one minute lifetime):

13 16 * * * cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
2 Likes

I'm a bit surprised that both the log entries are at 16:09h when the crontab entries are for 16:13h and 16:14h? Sure they belong together?

May be I missed to copy correct content. Here I tried it again. I made two attemps. One job created for 23:58 and another time at 00:01

-bash-3.2# crontab -l | tail -2
58 23 * * * cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
01 00 * * * cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
-bash-3.2#
-bash-3.2# tail -f  /var/cron/log
<  root 28826 c Thu Apr 18 16:13:00 2019 rc=2
>  CMD: unlink /var/log/apache/error_log
>  root 29897 c Thu Apr 18 16:14:00 2019
<  root 29897 c Thu Apr 18 16:14:00 2019 rc=255
>  CMD:  cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
>  root 26545 c Thu Apr 18 23:58:00 2019
<  root 26545 c Thu Apr 18 23:58:00 2019 rc=2
>  CMD: cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
>  root 3093 c Fri Apr 19 00:01:00 2019
<  root 3093 c Fri Apr 19 00:01:00 2019 rc=2
^C
-bash-3.2# ls -l /var/log/apache/error_log
/var/log/apache/error_log: No such file or directory
-bash-3.2#

But if I run command manually, it is able to create

-bash-3.2# cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
-bash-3.2# ls -l /var/log/apache/error_log
lrwxrwxrwx   1 root     root          18 Apr 19 00:03 /var/log/apache/error_log -> error_log.20190419
-bash-3.2# rm -f error_log
-bash-3.2#

To test, if cron is working with root, I made another entry of date command

32 00 * * * date>/tmp/date.out

-bash-3.2# tail -f  /var/cron/log
<  root 20623 c Fri Apr 19 00:20:22 2019
>  CMD: date > /tmp/date.out
>  root 10651 c Fri Apr 19 00:26:00 2019
<  root 10651 c Fri Apr 19 00:26:00 2019
>  CMD: cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
>  root 12318 c Fri Apr 19 00:27:00 2019
<  root 12318 c Fri Apr 19 00:27:00 2019 rc=2
>  CMD: cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
>  root 13871 c Fri Apr 19 00:28:00 2019
<  root 13871 c Fri Apr 19 00:28:00 2019 rc=2
>  CMD: cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log
>  root 23263 c Fri Apr 19 00:31:00 2019
<  root 23263 c Fri Apr 19 00:31:00 2019 rc=2
>  CMD: date>/tmp/date.out
>  root 25056 c Fri Apr 19 00:32:00 2019
<  root 25056 c Fri Apr 19 00:32:00 2019
^C
You have new mail in /var/mail/root
-bash-3.2# ls -l /tmp/date.out
-rw-r--r--   1 root     root          29 Apr 19 00:32 /tmp/date.out
-bash-3.2#

Not sure if "rc=2" is giving some indication

It certainly does and might be listed in the Solaris documentation, to which I have no access. cron jobs send their output - if any - by mail. You seem to have received mail(s). What do they say? You might want to add some debug info to your commands - intersperse some echo es.

rc=2 means exit status 2.

Look at root's mail with

Here it says in /var/mail/root

Your "cron" job on v911a-proxy1-prod
cd /var/log/apache && rm -f error_log && ln -s $(ls -r *error_log.* | head -1) error_log

produced the following output:

sh: syntax error at line 1: `(' unexpected

I am sorry about that. I made the mistake of copying the code from post #10 that you said you were using:

13 16 * * * cd /var/log/apache && ln -s $(ls -r *error_log.* | head -1) error_log
14 16 * * * unlink /var/log/apache/error_log

which used that same construct. But, with a pure Bourne shell from the 1980s being used by cron on Solaris 10, see what happens if you try:

13 16 * * * cd /var/log/apache && rm -f error_log && ln -s `ls -r *error_log.* | head -1` error_log

Note that this assumes that your error log file names do not contain any IFS characters (usually <space>, <tab>, and <newline>). If they could contain IFS characters you'll need to add double-quotes immediately before the opening back-quote and immediately after the closing back-quote.

1 Like

This worked very well.
Thanks for help and explanation