Search code examples
bashshelleofexit-codeheredoc

Exiting if a command returns an empty string when run in a heredoc (ssh ... <<EOF)


I want my command to exit with a status of failure (1), if the command returns no output in EOF. But I'm unable to use variable to store the command or store the output in a file.

For example:

#!/bin/bash
a='Some other commands in local machine'
ssh ubuntu@xx.xx.xx.xx << EOF
echo $a;
ldt=$(date +'%Y%m%d')
awk -v start="$(date +'%Y/%m/%d %H:%M' --date '-1000 min')" - F'[[:space:]]*[|][[:space:]]*' '
(\$4>=start) && /INFO: Server startup in/
' /some/file/path-\$ldt.log
EOF

Now, If the command gives an empty output, it should exit 1 and if some text is displayed, it should exit 0.

I'm unable to store the awk command in variable. If I store it in variable, the awk command doesn't work. Tried storing the output in the file but this also fails.

Please help me find a solution.


Solution

  • When you use an unquoted heredoc -- <<EOF -- expansions therein are run before it's fed on stdin to the command being invoked.

    This includes $(awk ...), making it difficult to correctly capture output from code generated on this way and operate on it later.

    So -- one thing you can do is use a quoted heredoc, and then go back to the approach you tried earlier (capturing the awk results and branching on them), and it should work correctly.

    The other thing you can do is have awk set its own exit status based on whether any matches are found.

    Setting Exit Status In awk

    #!/bin/bash
    a='Some other commands in local machine'
    printf -v args_q '%q ' "$a"
    
    ssh ubuntu@xx.xx.xx.xx "bash -s $args_q" <<'EOF'
      a=$1
      echo "$a"
      ldt=$(date +'%Y%m%d')
      awk -v start="$(date +'%Y/%m/%d %H:%M' --date '-1000 min')" -F'[[:space:]]*[|][[:space:]]*' '
        BEGIN { found=0 }
        ($4>=start) && /INFO: Server startup in/ { print $0; found=1; }
        END { if (found == 0) { exit(1) } else { exit(0) } }
      ' "/some/file/path-$ldt.log"
    EOF
    

    Setting Exit Status After awk

    #!/bin/bash
    a='Some other commands in local machine'
    printf -v args_q '%q ' "$a"
    
    ssh ubuntu@xx.xx.xx.xx "bash -s $args_q" <<'EOF'
      a=$1
      echo "$a"
      ldt=$(date +'%Y%m%d')
      awk_result=$(
        awk -v start="$(date +'%Y/%m/%d %H:%M' --date '-1000 min')" -F'[[:space:]]*[|][[:space:]]*' '
          BEGIN { found=0 }
          ($4>=start) && /INFO: Server startup in/ { print $0; found=1; }
          END { if (found == 0) { exit(1) } else { exit(0) } }
        ' "/some/file/path-$ldt.log"
      )
      [[ $awk_result ]] && echo "$awk_result"
      [[ $awk_result ]] # success only if awk_result is nonempty
    EOF
    

    Note that this only works if <<EOF has been changed to <<'EOF', such that the awk command is evaluated remotely.