1

Given

hasArgs=a:b:c:
x=b
if [[ ${hasArgs} = *$x:* ]] ; then …

I wish I could replace the above double brackets test with a less Bash specific alternative (meaning no subshell/command etc.)

Parameter expansion does not help because it does not expend variables.

if [ "${hasArgs}" != "${hasArgs#$x:}" ] ; then …

Is there any simple (one line) solution that would fit this use case?

  • This is not bash specific but ksh specific. Double brackets have been introduced by ksh88. – schily Aug 3 '18 at 22:38
  • I wanted to say POSIX compliant, but thank's I will remember where double brackets are coming from. – Stphane Aug 4 '18 at 8:57
  • Double brackets have intentionally not put in to POSIX even though ksh88 was the master for the POSIX shell. – schily Aug 4 '18 at 9:01
2

Actually, you can use the standard parameter expansions here (you were just missing the wildcard):

$ args=a:b:c:
$ x=b
$ echo "${args%$x:*}"
a:
$ if [ "$args" != "${args#*$x:}" ]; then echo 'b: is present'; fi
b: is present

(or equally "${args%$x:*}")

The downside is that you need to have the colon after b, so a:b or a plain b wouldn't match, and it would also match a:bb:c. ([[ $var = *$x:* ]] as well as the obvious pattern match with case have the same disadvantage.)

Matching all of b, b:c, a:b, a:b:c, while not matching a:bb:c would be a bit more tricky. All I can think of is something like this:

args=a:b:c
x=b
IFS=:                   # affects globally
set -f                  # affects globally...
for x in $args; do
    if [ "$x" = "b" ]; then
        echo "b is present"
    fi
done

Unless you want to write all the cases out:

args=a:b:c
x=b
found=0
case "$args" in
    $x)     found=1;;
    $x:*)   found=1;;
    *:$x)   found=1;;
    *:$x:*) found=1;;
esac
if [ "$found" = 1 ]; then ...; fi

Much easier with regexes (in Bash):

args=b:c
x=b
if [[ $args =~ (^|:)$x(:|$) ]]; then
    echo "b found"
fi
  • So (some?) parameter expansion(s) actually evaluate variables in their pattern prior to expansion, I missed the wildcard. Since there will always have a colon after the x variable, I can safely use this expression. – Stphane Aug 4 '18 at 9:03
  • 2
    @Stphane, they all do, on the right hand side that takes a string, not on the left part that takes a parameter name. So, ${x#$y} works, but ${${x#foo}%bar} doesn't. Except in zsh. – ilkkachu Aug 4 '18 at 9:21
6

It's not a one-liner, but this is quite readable and can be expanded to check for any number of arguments:

hasArgs="a:b:c"
x=b
case "$hasArgs" in
    *$x*)
        echo "$x is present"
        ;;
esac
  • I should have told about this but I already use a case structure somewhere else in my script (meaning I am aware of the glob capability), this is the reason why I asked for a one-liner. But not everyone may be aware of this so your answer is surely welcome. – Stphane Aug 4 '18 at 8:07
3

The following will work in sh:

if echo "$hasArgs" | grep -q "$x"; then
  • 2
    Congrats on 10k! – slm Aug 3 '18 at 22:43
  • Looks like a good alternative to [ since both are external executables. (+ one-liner) – Stphane Aug 4 '18 at 8:45

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.