夏期劇場 夏期劇場 - 2 months ago 11
Linux Question

Linux Script: Saving Memory print into text file via Crontab always blank

In my CentOS, i'm trying to print the CPU USAGE and FREE MEMORY output numbers into a text file. But when i typing in the terminal, it is all fine. But when it is executed via the

crontab
the MEMORY output is always blank.

Manually typing in terminal:

# echo CPU: `top -b -n1 | grep "Cpu(s)" | awk '{print $2 + $4}'`, RAM: `awk '/^Mem/ {print $4}' <(free -m)` >> ~/stats.txt
# cat ~/stats.txt
CPU: 3.8, RAM: 1307


Same command in Crontab:

*/10 * * * * echo CPU: `top -b -n1 | grep "Cpu(s)" | awk '{print $2 + $4}'`, RAM: `awk '/^Mem/ {print $4}' <(free -m)` >> ~/stats.txt


Then inside the Text file:

# cat ~/stats.txt
CPU: 3.4, RAM:
CPU: 4.1, RAM:
CPU: 3.9, RAM:


Why is the RAM output always blank please?

Answer

You are using process substitution in your command:

<(free -m)

. This is a Bash feature that is not present in the standard POSIX shell, and not even in Bash on some platforms.

Unless you specify otherwise by setting the SHELL variable in your crontab, cron runs your commands via /bin/sh. When started this way, bash does its best to emulate the POSIX shell in most respects. That includes refusing to recognize process substitutions. On my present system, for example:

$ /bin/bash -c "awk '/^Mem/ {print \$4}' <(free -m)"
11603

but

$ /bin/sh -c "awk '/^Mem/ {print \$4}' <(free -m)"
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `awk '/^Mem/ {print $4}' <(free -m)'

Since your command is (presumably) producing an error, it may be that cron is sending you email about that.

You could set SHELL=/bin/bash in your crontab, but I don't see why you need process substitution in the first place. awk reads from standard input if you don't specify a file name, so you could as easily pipe the output of free into it.

$ /bin/sh -c "free -m | awk '/^Mem/ {print \$4}'"
11612

The corresponding crontab line would be

*/10 * * * * echo CPU: `top -b -n1 | grep "Cpu(s)" | awk '{print $2 + $4}'`, RAM: `free -m | awk '/^Mem/ {print $4}'` >> ~/stats.txt

That's more standard, easier (for me) to read, and more internally consistent.

Comments