1

I have a script that executes all commands until it reaches the if statement:

Script:

#!/bin/bash

######VARIABLES#######
#grep return value
gret=$?

######LOGIC#######
cd /home/logs
echo "Enter filename: "
read filenamex
echo "filename : ${filenamex}"
grep ${filenamex} log.dat | grep "End receiving ftp file:"
echo $?

if [ {gret} -ne 0 ]; then
   echo "{filenamex} cannot be found in the recent logs. We will now check the old logs."
   sleep 3
   grep ${filenamex} log.dat* | grep "End receiving ftp file:"
fi

Can anyone please help me execute the script so that if I cannot grep the desired value, the script will execute the if statement?

0

1 Answer 1

8

The main issue with your code is a missing $ in the test ({gret} should be ${gret}, or better yet, "$gret"), and that you never assign the exit status of grep to the gret variable (which is not actually necessary if you use grep directly with if, as described below).

You may use the exit status of a command in an if statement directly. The code below also expects a filename as a command line argument instead of asking for it interactively.

#!/bin/sh

if [ -z "$1" ]; then
    echo 'Expected to get a filename as argument'
    exit 1
fi >&2

if ! grep -Fe "$1" /home/logs/log.dat | grep -F 'End receiving ftp file:'
then
    echo 'Checking older logs...' >&2
    grep -Fe "$1" /home/logs/log.dat?* | grep -F 'End receiving ftp file:'
fi

The code above uses -F with grep to avoid interpreting the pattern as a regular expression, and -e to avoid mistaking the pattern as a set of options if it starts with a dash. If you want to use the given string as a regular expression, remove -F from the first grep in each grep pipeline.

The filename globbing pattern /home/logs/log.dat?* matches names under /home/logs that start with log.dat, without matching the actual name log.dat itself. It does this by requiring at least one extra character after the name's initial log.dat prefix.

I turned the script into a sh script, as it uses no bash-specific features.


Refactoring the code above to avoid repeating virtually the same grep pipeline twice:

#!/bin/sh

if [ -z "$1" ]; then
    echo 'Expected to get a filename as argument'
    exit 1
fi >&2

do_grep () {
    pattern=$1; shift

    grep -Fe "$pattern" -- "$@" |
        grep -F 'End receiving ftp file:'
}

if ! do_grep "$1" /home/logs/log.dat; then
    echo 'Checking older logs...' >&2
    do_grep "$1" /home/logs/log.dat?*
fi
3
  • Thank you, I tried your version, but it still does not give me the desired output. Your script ends on "Expected to get a filename as argument" I am trying to build a script that if I grep in log.dat a filename, and there is no output, then the script will grep in an older log.dat file for the filename. Sep 5 at 12:28
  • @UnisJoneth Run the script with the filename as a command line argument: ./thescript some-filename. This is what the error message means and what I mentioned in my answer.
    – Kusalananda
    Sep 5 at 12:32
  • @UnisJoneth To qualify my previous comment: It is usually preferable to take user input in the form of command line arguments rather than interactively. This way, the user can make use of their shell's command line history and auto-completion etc., and they are also able to use the script seamlessly in their own scripts without requiring interactive involvement (which might not be possible in some instances, as when running cron jobs, for example).
    – Kusalananda
    Sep 6 at 6:02

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.