1

I want the user to be prompted with a question and then supply the answer, which will be stored under a variable named i, then if the answer (which is a file) exists and is writable, it reads it and greps things within the file and write those things to a new one. If the file doesn't exists or the user doesn't have enough permissions over that file, then a warning is prompted, the program sleeps for 3 seconds and the loops starts again. Why isn't it working? The warning simply won't go away, neither will the loop keep going.

echo "$(tput setaf 4)  Tell me where the file is:"
printf "\n"

a=false
while [ $a=true ]; do
    read i
    if [ -w $i ]
        then cat $i | grep stuff > i2
    else
        a=true
        printf "Oh something is wrong, try again!"
            sleep 3
    fi
done
2

You have syntax and logical errors.

The $a=true is just a string, NOT a comparison operation. Separate with spaces so the comparison will take place: "$a" = true.

With that working, the loop won't be entered at all, as you set a=false upfront.

SHOULD you finally get into the loop, you won't be able to exit, as a is never set to anything but true, nor is another exit mechanism (e.g. break) provided.

1

As others have pointed out, you have logical errors and syntax errors in your code. The ShellCheck site is good for weeding out the syntax errors.

Here's my take on this. I have two versions of the code. The first one (which I prefer) has no user interaction but takes a pathname on the command line. The second one interactively asks for a pathname.

The reason that the first one does not interactively prompt for a pathname is that it makes little difference if the user of the script writes the pathname on the command line or at your script's prompt, and having the script prompt for the pathname disqualifies it from being used from e.g. a cron job or anywhere else where there may not be a terminal attached.

#!/bin/sh

pathname=$1

if ! grep 'pattern' <$pathname >i2; then
    echo 'Something is wrong' >&2
fi

The echo above will be executed when

  • the file in $pathname can't be read, or
  • the file i2 can't be written to, or
  • the pattern was not found in $pathname (this is different from your code, but see below).

The error message is written to standard error, as is the custom with diagnostic messages in general.

With interactive prompting and delay:

#!/bin/bash

while true; do
    read -r -p 'Pathname: ' pathname

    if grep 'pattern' <$pathname >i2; then
       break
    fi

    echo 'Something is wrong' >&2
    sleep 3
done

Here, we have an infinite loop that read from the user and break out of the loop if the grep call went ok. If grep failed for whatever reason (one of the three reasons above), the pathname is prompted for again.


Both pieces of code with a separate test for a readable file (the grep is allowed to fail by not finding anything or not being able to write to its output file.

First the non-interactive version:

#!/bin/sh

pathname=$1

if [ ! -r "$pathname" ]; then
    echo 'Something is wrong' >&2
fi

grep 'pattern' <$pathname >i2

Then the interactive version:

#!/bin/bash

while true; do
    read -r -p 'Pathname: ' pathname

    if [ -r "$pathname" ]; then
       grep 'pattern' <$pathname >i2
       break
    fi

    echo 'Something is wrong' >&2
    sleep 3
done

Or, an interactive version where the loop only deals with user input and validation:

#!/bin/bash

while true; do
    read -r -p 'Pathname: ' pathname

    [ -r "$pathname" ] && break

    echo 'Something is wrong' >&2
    sleep 3
done

grep 'pattern' <$pathname >i2
0

Try using simply break to stop infinite loop like this:

echo "$(tput setaf 4)  Tell me where the file is:"
echo # This prints empty line like printf "\n"

while true; do # 'while true' or 'while :' is infinite loop
    read i
    if [ -r $i ]    # You probably mean -r (readable) and not -w (writable)
    then
        cat $i | grep stuff > i2
        break # 'break' ends loop
    else
        echo -n "Oh something is wrong, try again!" # 'echo -n' means print without newline character
        sleep 3
    fi
done

Modified places have comments with description.

  • grep <$i >i2 rather than the cat. Also, quote variable expansions where needed, like in the test. – Kusalananda Oct 14 '18 at 20:13

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.