123

I'm trying to write a script where I want to check if any of the parameters passed to a bash script match a string. The way I have it setup right now is

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

but there might be a large number of parameters, so I was wondering if there is a better way to do this?

Thanks

EDIT: I tried this chunk of code out, and called the script with the option, -disableVenusBld, but it still prints out "Starting build". Am I doing something wrong? Thanks in advance!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi
iman453
  • 1,575

6 Answers6

97

It looks like you're doing option handling in a shell script. Here's the idiom for that:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(There are a couple of conventions for indenting the ;;, and some shells allow you to give the options as (--opt1), to help with brace matching, but this is the basic idea)

Norman Gray
  • 1,476
93

This worked for me. It does exactly what you asked and nothing more (no option processing). Whether that's good or bad is an exercise for the poster :)

if [[ "$*" == *"YOURSTRING"* ]]
then
    echo "YES"
else
    echo "NO"
fi

This takes advantage of special handling of $* and bash super-test [[]] brackets.

Toto
  • 19,304
Rich Homolka
  • 32,350
10

How about searching (with wildcards) the whole parameter space:

if [[ $@ == *'-disableVenusBld'* ]]
then

Edit: Ok, ok, so that wasn't a popular answer. How about this one, it's perfect!:

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2: Ok, ok, maybe this isn't perfect... Think it works only if -param is at the start of the list and will also match -paramXZY or -paramABC. I still think the original problem can be solved very nicely with bash string manipulation, but I haven't quite cracked it here... -Can you??

Rich
  • 233
8
[[ "$@" =~ '-disableVenusBld' ]] && disableVenusBld=true
[[ "$@" =~ '-disCopperBld'    ]] && disCopperBld=true
[[ "$@" =~ '-disableTest'     ]] && disableTest=true
[[ "$@" =~ '-disableUpdate'   ]] && disableUpdate=true

or more generally

[[ "$@" =~ 'your-string' ]] && ( doSomething )

Edit Dec 2023: resolves comment below, using anchors for exact match (a little less readable but fewer surprises):

#!/bin/bash

[[ "$*" =~ ^-disableVenusBld$ ]] && disableVenusBld=true [[ "$*" =~ ^-disCopperBld$ ]] && disCopperBld=true [[ "$*" =~ ^-disableTest$ ]] && disableTest=true [[ "$*" =~ ^-disableUpdate$ ]] && disableUpdate=true

user1016765
  • 189
  • 1
  • 3
5
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

If you need to test only the parameters starting at $3, do the search in a function:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

But I wonder why you're trying to do this in the first place, it's not a common need. Usually, you'd process options in order, as in Dennis's answer to your previous question.

0

If your arguments do not contain newlines:

printf '%s\n' "$@" | grep -Fqx -- "YOUR_STRING"

Explanation:

  • The printf command will print the remaining arguments in a certain format. Specifically, delimiting the arguments with a newline \n.
  • grep goes line-by-line and searches for your string.
  • -F or --fixed-strings means treating the search pattern as a raw string (not a regex)
  • -q or --quiet means quiet searching. Only succeeds or fails but doesn't produce output.
  • -x or --line-regexp means that the search pattern is the whole line, so that you wouldn't find Barcelona when searching for on. (The name is confusing as we're not using regex's, yes, but it's correct.)

Example:

arr=(1 2 3 a b c)
printf '%s\n' "${arr[@]}"
1
2
3
a
b
c
printf '%s\n' "${arr[@]}" | grep -Fqx -- "1"  # succeeds
printf '%s\n' "${arr[@]}" | grep -Fqx -- "2"  # succeeds
printf '%s\n' "${arr[@]}" | grep -Fqx -- "3"  # succeeds
printf '%s\n' "${arr[@]}" | grep -Fqx -- "4"  # fails
printf '%s\n' "${arr[@]}" | grep -Fqx -- "a"  # succeeds

Credits:

VasyaNovikov
  • 3,656