2

I have a for loop in bash that is;

for Names in `grep "name" $people`
do
    echo "name is $name"
done

How can I have an if statement that says something like;

for Name in `grep "name" $people`
# Make sure we found some names
if [ "count of $Name=0" ]
then
    echo "no names found"
fi

# Else, if we did grep out a list of names, print them
do
    echo "name is $Name"
done

4 Answers 4

5

Add a compound conditional test (&&) to print the debug text if the for block has a return code of 0 (meaning it never got into the loop and called false):

for NAME in $(grep "name" $people)
do
    echo "Name is ${NAME}"
    false
done && echo "no names found"

If you don't like the way it reads, just invert the for:

! for NAME in $(grep "name" $people)
do
    echo "Name is ${NAME}"
    false
done || echo "no names found"
Sign up to request clarification or add additional context in comments.

2 Comments

The logic is kind of backwards. I suppose it could be straightened out with a tactical negation somewhere.
I like this approach very much, thank you. It has taught me a new way of looking at the logic of this problem but as tripleee said, a little backwards, and I want others to read my script with ease.
1

Perform the grep first and store its result in a variable. Then check whether something is returned, e.g., with wc. If so, run the loop with the result of grep.

2 Comments

This seems like the simplest, most straight for ward solution. Thank you :D
In bash the KISS principle holds much more than any other language (except perl of course...)
1

You cannot do that inside the loop. Set a flag to true inside the loop, or check the number of arguments.

set -- `grep "$name" people`
case $# in 0) echo no names found >&2;;
  *) for Name; do # special form - loop over $*
      echo name is "$Name"
  done ;;
esac

1 Comment

I like this method tripleee, using the case statement leaves good room to add in additional checks I could perform instead of just "there is data", "there is no data". Although, the answer I accepted was the most simple and direct one, I think I will be trying this out in another script that is a bit more complicated, thank you!
1

This might work for you:

sed -n '/name/{h;s//name is &/p};${x;/./!s/^/no names found/p}' $people

This presumes $people is a file of at least one line

EDIT: Explanation - -n prevent default printout to stdout. Search for name in each line of file $peopleand if found copy line to hold space (HS) and prepend name is to value and printout. On last line swap to HS and if it doesn't contain anything printout no names found.

A bash alternative is:

names=($(grep "name" $people))
((${#names[@]})) && printf "name is %s\n" "${names[@]}" || printf "no names found\n"

EDIT: Populate the array names with grep output. Test the size of the array names and if it is not zero, prepend name is to each value and printout else printout no names found.

1 Comment

Thanks potong. I'm a total sed newb so I can't read the example you have provided and understand it 100%. However, reading you bash alternative I am very impressed, that's awesome! This has given me a new look on the logic of the situation and of Bash, thanks very much :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.