3

I'm new to shell scripting and I'd like to know if there is maybe a better solution then the one I figured out:

I want to check if a user is in a list and if yes than the script should terminate with the exit_program function:

$USER is defined as somebody who logs into the system

My solution (it works) is:

$IGNORE_USER="USER1 USER2 USER3"

if [ ! -z "$IGNORE_USER" ]; then
for usr in $IGNORE_USER
    do
    if $USER = $usr; then
        exit_program "bye bye"    
    fi
    done
fi
  • You don't need to loop over your array of users. See here – xenoid Aug 5 '18 at 16:38
  • If you have a working script and want it reviewed, consider codereview.stackexchange.com – kojiro Aug 5 '18 at 20:15
  • Welcome to Unix & Linux! If you believe that the code works correctly, consider presenting your work (with its unit tests) in a more-complete fashion over at Code Review. You'll likely get some suggestions on making it more efficient, easier to read, and better tested. Before you do that, make sure to read A guide to Code Review for Stack Overflow users first, as some things are done differently over there - e.g. question titles should simply say what the code does, as the question is always, "How can I improve this?". – Toby Speight Aug 6 '18 at 12:50
11

That script does not work.

You have a syntax error on the first line in that an assignment to IGNORE_USER should not dereference the variable with $. There is another syntax error in your if statement. Use [ "string1" = "string2" ] to compare strings.

Your code relies on using $IGNORE_USER unquoted. This splits the string on whitespaces, which is what you want to do. In the most general case, this is not what you want to do though, as the items in the list may well contain whitespace characters that should be preserved. The shell would also perform filename generation (globbing) on the values in the string if it's used unquoted.

It would be better to use an array for this as you're dealing with separate items (usernames). Whenever you want to treat separate items as separate items, don't put them inside a single string. Doing so would potentially make it hard to distinguish one item from another.

Suggestion:

ignore=( 'user1' 'user2' 'user3' )

for u in "${ignore[@]}"; do
    if [ "$USER" = "$u" ]; then
        exit_program 'bye bye'
    fi
done

This assumes that exit_program takes care of exiting the program. If not, add exit after calling exit_program. There is no need to test whether the ignore array is empty as the loop would not run a single iteration if it was.

In the code above, "${ignore[@]}" (note the double quotes) would expand to the list of usernames, each username individually quoted and protected from further word splitting and filename generation.

Related:


For a version that is not specific to bash, but that would run in any POSIX-like shell:

set -- 'user1' 'user2' 'user3'

for u do
    if [ "$USER" = "$u" ]; then
        exit_program 'bye bye'
    fi
done

This uses the list of positional parameters as the list of usernames to ignore instead of an array.

4

grep solution

Use the "-w" feature of grep, to match a word. Daresay it won't work on older grep implementations, such as Solaris, AIX etc.

echo $IGNORE_USER | grep -qw $USER && exit_program 'bye bye'

Try it online!

bash internal solution

Go entirely bash, and don't rely on grep.

bash doesn't allow a construct of =~ regex unless you run shopt -s compat31 first. So by using the =~ $(echo regex) we can overcome this. We use double quotes in this example, so that $USER gets expanded, and in so doing we need to escape out the \b to be \\b.

[[ $IGNORE_USER =~ $(echo "\\b$USER\\b") ]] && exit_program 'bye bye'

Try it online!

  • 1
    I'd say your grep solution is the most elegant one, specially as it relies on a simple regular expression. I believe it also runs faster than manually iterating through an array, though you might not want to quote me on that. – Telmo Trooper Aug 6 '18 at 11:37

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.