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 &)


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 &)'


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?

  • In Attempt Solution 2, Try 2: sh might point to dash or bash in POSIX mode, either way you won't be able to use process substitution <(…). – phk Oct 19 '16 at 20:32
  • @phk it is Ubuntu so it's using dash it looks like. Thanks for the info. – mdo123 Oct 19 '16 at 21:10

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 &)'
  • thanks for your help @ilkkachu it lead me to a better answer and understanding of how it works. I've updated my answer. – mdo123 Oct 20 '16 at 18:35

Found Alexander Batischev's answer to use sudo su -c.

Solution (OLD):

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


Based on ilkkachu's answer I did some more testing and found a new solution.

  1. First, in response to ilkkachu's answer about sudo su being redundant. If I remove sudo from the command I'm prompted to enter a password.

  2. Second, in response to ilkkachu's answer about a subshell not being useful. This is true. However, the command without the subshell only returns if the log is actively being written to for some reason. Otherwise it hangs. When using the subshell the cmd returns even if the log is not actively being written to. So I prefer subshell command, but sh doesn't support subshells.

    Also, I noticed when testing on an active log that the use of using bash vs. sh has different time. For some reason sh takes a second longer to respond then bash.

    For these two reasons (using subshell and delay in sh over bash) I decided sh is not suitable solution.

  3. Third, in response to ilkkachu's answer regarding the unecessary & for tail. That is correct, I removed it and it had no impact.


sudo su vs. su

//prompts for password w/out sudo
su -c 'timeout 200 grep -q "Started .*Application" <(tail -n100 -f /path/to/nameOfLog.log &)''

sudo su -c 'timeout 200 grep -q "Started .*Application" <(tail -n100 -f  /path/to/nameOfLog.log  &)'

using sh -c

//either works (sudo or not using sudo)
//but both won't work unless log is actively being written to for some reason    

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

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

using bash

//either works (sudo or not using sudo)

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

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

NEW Solution:

I realized I left out one important detail. Which is that this was being executed via a terraform remote-exec provisioner. Terraform creates a local .sh script under /tmp/ on the server for any inline commands. The communicator/ssh/communicator.go sets #!/bin/sh at the top of the scripts which means they are using sh. So since I'm using a subshell I need to use bash. The use of sudo is not necessary and was my misunderstanding. However, you can still use sudo. So the answer I went with is either of the using bash commands listed under the Summary above.

P.S. my target servers in this case were running 14.04.1-Ubuntu. Running ls -l /bin/sh shows /bin/sh -> dash so actually I'm not using sh but dash. So it appears dash has the same setbacks as sh.

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.