Home > Net >  Bash script with multiline variable
Bash script with multiline variable

Time:02-01

Here is my code

vmname="$1"
EXCEPTLIST="desktop-01|desktop-02|desktop-03|desktop-04"
if [[ $vmname != @(${EXCEPTLIST}) ]]; then
    echo "${vmname}"
else
echo "Its in the exceptlist"
fi

The above code works perfectly but my question is , the EXCEPTLIST can be a long line, say 100 server names. In that case its hard to put all that names in one line. In that situation is there any way to make the variable EXCEPTLIST to be a multiline variable ? something like as follows:

    EXCEPTLIST="desktop-01|desktop-02|desktop-03| \n
                desktop-04|desktop-05|desktop-06| \n
                desktop-07|desktop-08"

I am not sure but was thinking of possibilities.

Apparently I would like to know the terminology of using @(${})- Is this called variable expansion or what ? Does anyone know the documentation/explain to me about how this works in bash. ?

CodePudding user response:

One can declare an array if the data/string is long/large. Use IFS and printf for the format string, something like:

#!/usr/bin/env bash

exceptlist=(
 desktop-01
 desktop-02
 desktop-03
 desktop-04
 desktop-05
 desktop-06
)

pattern=$(IFS='|'; printf '@(%s)' "${exceptlist[*]}")

[[ "$vmname" != $pattern ]] && echo good

In that situation is there any way to make the variable EXCEPTLIST to be a multiline variable ?

With your given input/data an array is also a best option, something like:

exceptlist=(
  'desktop-01|desktop-02|desktop-03'
  'desktop-04|desktop-05|desktop-06'
  'desktop-07|desktop-08'
)

Check what is the value of $pattern variable one way is:

declare -p pattern

Output:

declare -- pattern="@(desktop-01|desktop-02|desktop-03|desktop-04|desktop-05|desktop-06)"

  • Need to test/check if $vmname is an empty string too, since it will always be true.

  • On a side note, don't use all upper case variables for purely internal purposes.

  • The $(...) is called Command Substitution.

    • See LESS= '/\ *Command Substitution' man bash

In addition to what was mentioned in the comments about pattern matching

  • See LESS= /'(pattern-list)' man bash

  • See LESS= /' *\[\[ expression' man bash

CodePudding user response:

s there any way to make the variable EXCEPTLIST to be a multiline variable ?

I see no reason to use matching. Use a bash array and just compare.

exceptlist=(
   desktop-01
   desktop-02
   desktop-03
   desktop-04
   desktop-05
   desktop-06
)

is_in_list() {
   local i
   for i in "${@:2}"; do
      if [[ "$1" = "$i" ]]; then
          return 0
      fi
   done
   return 1
}

if is_in_list "$vmname" "${EXCEPTLIST[@]}"; then
    echo "is in exception list ${vmname}"
fi

@(${})- Is this called variable expansion or what ? Does anyone know the documentation/explain to me about how this works in bash. ?

${var} is a variable expansion.

@(...) are just characters @ ( ).

From man bash in Compund commands:

   [[ expression ]]

          When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules
          described below under Pattern Matching, as if the extglob shell option were enabled. ...

From Pattern Matching in man bash:

          @(pattern-list)
                 Matches one of the given patterns

[[ command receives the @(a|b|c) string and then matches the arguments.

CodePudding user response:

There is absolutely no need to use Bash specific regex or arrays and loop for a match, if using grep for raw string on word boundary. The exception list can be multi-line, it will work as well:

#!/usr/bin/sh

exceptlist='
desktop-01|desktop-02|desktop-03|
deskop-04|desktop-05|desktop-06|
desktop-07|deskop-08'

if printf %s "$exceptlist" | grep -qwF "$1"; then
  printf '%s is in the exceptlist\n' "$1" 
fi

CodePudding user response:

I wouldn't bother with multiple lines of text. This is would be just fine:

EXCEPTLIST='desktop-01|desktop-02|desktop-03|'
EXCEPTLIST ='desktop-04|desktop-05|desktop-06|'
EXCEPTLIST ='desktop-07|desktop-08'

The @(...) construct is called extended globbing pattern and what it does is an extension of what you probably already know -- wildcards:

VAR='foobar'
if [[ "$VAR" == fo?b* ]]; then
    echo "Yes!"
else
    echo "No!"
fi

A quick walkthrough on extended globbing examples: https://www.linuxjournal.com/content/bash-extended-globbing

CodePudding user response:

#!/bin/bash

set  o posix
shopt -s extglob

vmname=$1

EXCEPTLIST=(
    desktop-01 desktop-02 desktop-03
    ...
)

if IFS='|' eval '[[ ${vmname} == @(${EXCEPTLIST[*]}) ]]'; then
    ...

CodePudding user response:

There are multiple solutions to your problem.

Solution 1, since all the desktop has the same desktop-0 prefix and only differ in the last letter, we can make use of {,} or {..} expansion as follows:

vmname="$1"
found=0
for d in desktop-{01..08}
do
  if [[ "$vmname" == $d ]]; then
    found=1
    break
  fi
done
if (( found )); then
  echo "It's in the exceptlist"
fi

Solution 2, sometimes, it is good to provide a list in a maintainable clear text list. We can use a while loop and iterate through the list

vmname="$1"
found=0
while IFS= read -r d
do
  if [[ "$vmname" == $d ]]; then
    found=1
    break
  fi
done <<EOF
desktop-01
desktop-02
desktop-03
desktop-04
desktop-05
desktop-06
desktop-07
desktop-08
EOF
if (( found )); then
  echo "It's in the exceptlist"
fi

Solution 3, we can desktop the servers using regular expressions:

vmname="$1"
if [[ "$vmname" =~ ^desktop-0[1-8]$ ]]; then
  echo "It's in the exceptlist"
fi

Solution 4, we populate an array, then iterate through an array:

vmname="$1"
exceptlist=()
exceptlist =(desktop-01 desktop-02 desktop-03 deskop-04)
exceptlist =(desktop-05 desktop-06 desktop-07 deskop-08)
found=0
for d in ${exceptlist[@]}
do
  if [[ "$vmname" == "$d" ]]; then
    found=1
    break;
  fi
done
if (( found )); then
  echo "It's in the exceptlist"
fi
  •  Tags:  
  • bash
  • Related