Shell – bash syntax – wrapping command inside sudo :: tail logs until string found with timeout using Terraform

grepsubshellsudotailtimeout

Goal: using sudo execute a one line cmd to tail a log until a string is found and then exit 0. If the string is not found within a given timeout, exit anything but 0.

Attempted Solution 1: Originally I did not have timeout as a requirement and so after some research I landed on using:

sudo sh -c '( tail -n1 -f /path/to/nameOfLog.log & ) | grep -q "Started .*Application"'

However, now I do have timeout as a requirement. I could not figure out how to get timeout to work with this command until I found Ondra Žižka's answer. So my new cmd became:

Attempt Solution 2:

timeout 5 grep -q "Started .*Application" <(tail -n1 -f /path/to/nameOfLog.log &)

But this obviously is not using sudo permissions, which is the current issue I need to solve. Below are some variations I've tried which failed

Try 1 : (add sudo in front of cmd)

sudo timeout 5 grep -q "Started .*Application" <(tail -n1 -f /path/to/nameOfLog.log &)

Output:

grep: /dev/fd/63: No such file or directory

Try 2: (try to wrap cmd in subshell)

sudo sh -c 'timeout 5 grep -q "Started .*Application" <(tail -n1 -f /path/to/nameOfLog.log &)'

Output:

sh: 1: Syntax error: "(" unexpected

Can someone show me and explain the issue and how to fix it so I can run this command using sudo? Also, do I really need to restructure cmd from Attempted Solution 1 to get it to work with timeout as well?

Best Answer

1) I'm not sure if the subshell (or backgrounding) is useful here:

sudo sh -c '( tail -n1 -f /path/to/nameOfLog.log & ) | grep -q "Started .*Application"'

shouldn't a simple pipe do?

sudo sh -c 'tail -n1 -f /path/to/nameOfLog.log | grep -q "Started .*Application"'

2) Your "try 1":

sudo timeout 5 grep -q "Started .*Application" <(tail -n1 -f /path/to/nameOfLog.log &)

expands the input redirection <() on the command line that runs the sudo, not inside sudo. The filehandle it opens isn't passed through sudo to grep, so grep can't open the /dev/fd/63 pseudo-file.

Same thing about backgrounding the tail here, it shouldn't be necessary.


3) And, as phk commented, your "try 2":

sudo sh -c 'timeout 5 grep -q "Started .*Application" <(tail -n1 -f /path/to/nameOfLog.log &)'

...explicitly runs sh, and not bash or any other more featureful shell. Plain standard sh doesn't support <(), and neither does dash which is used as sh on Debian and Ubuntu.

When you run su instead, it runs root's login shell, which is likely to be bash on Ubuntu. But using both sudo and su is redundant, they're both made to elevate privileges, and after sudo you're already running elevated privilege, so no need for su. Instead, if you want to run a shell inside sudo, just say explicitly which one:

sudo bash -c 'timeout 5 grep -q "Started .*Application" <(tail -n1 -f /path/to/nameOfLog.log &)'
Related Question