-2

I am attempting to use a regular expression within a Bash conditional expression and Bash does not like my syntax. The code follows:

    declare -a sshkeys
    declare sshpath="$HOME/.ssh"
    if [[ -f "$sshpath/ssh_keys" ]]; then
        mapfile -t sshkeys <"$sshpath/ssh-keys"
    fi
    declare pattern="^(:alnum::alnum:*)(:blank:|#|$)"
    for i in {"$sshkeys[@]"}
    do
        if [[ [ "$i" ~= "$pattern" ] && [ -e "$sshpath/$BASH_REMATCH[1]" ] ]]; then
            ssh-add "$sshpath/$BASH_REMATCH[1]" </dev/null 1>&-
        fi
    done

Bash produces the following error message:

source .profile
bash: .profile: line 49: conditional binary operator expected
bash: .profile: line 49: syntax error near `"$i"'
bash: .profile: line 49: `        if [[ [ "$i" ~= "$pattern" ] && [ -e "$sshpath/$BASH_REMATCH[1]" ] ]]; then'

It looks like Bash is not happy with regular expression tests in complex conditional expressions. Can anyone say how I should be doing this?

Jonathan
  • 2,635
  • 3
  • 30
  • 49
  • 1
    Did you mean `pattern='^([[:alnum:]]*)([[:blank:]#]|$)'`? – Wiktor Stribiżew Sep 04 '20 at 14:36
  • what's in `$i`? what does `echo ${i}` show? – markp-fuso Sep 04 '20 at 14:36
  • Probably try http://shellcheck.net/ before asking for human assistance, though it probably can't guess what you mean when you're this far off. – tripleee Sep 04 '20 at 14:41
  • Wiktor Stribizew The expression must have a least one alphanumeric character but may contain more and is delimited by one of a white space character, a # signaling the start of a comment or a $ for end of line. – Jonathan Sep 04 '20 at 14:41
  • @mark-fuso It contains the file name of a file in a directory which is then combined with the path to the directory to access the file. – Jonathan Sep 04 '20 at 14:44
  • I modified the script to use nested if statements and got the following result: ``` bash: [: ~=: binary operator expected bash: [: ~=: binary operator expected ~~~ The relevant source code follows: ``` if [ "$i" ~= $pattern ]; then if [[ -f "$sshpath/${BASH_REMATCH[1]}" ]]; then ssh-add "$sshpath/${BASH_REMATCH[1]}" &- fi fi ``` – Jonathan Sep 04 '20 at 16:30
  • `for i in {"$sshkeys[@]"}`, while it will work, it will add an unwanted prefix of `{` on the first array item, and add an unwanted suffix of `}` on the last array item ... hence my suggestion to verify that `$i` does in fact contain what you think it does – markp-fuso Sep 04 '20 at 16:32
  • also, the nested square braces ... `[[ [ ... ] && [ ... ] ]]` is invalid; see Benjamin's answer for a fix; alternatively you can replace the internal `[]`'s with parens, eg, `[[ ( ... ) && ( ... ) ]]` – markp-fuso Sep 04 '20 at 16:34

2 Answers2

2
  • There seems to be a typo (ssh_keys, but then ssh-keys)

  • You're using incorrect character classes in the regular expression: it should probably be something like

    ^([[:alnum:]]+)([[:blank:]]|#|$)
    
  • To loop over array elements, use

    for i in "${sshkeys[@]}"
    
  • The operator to compare to a regex is =~, not ~=

  • The pattern must be unquoted after =~, or it is interpreted as a literal string

  • You can't do this for multiple conditions:

    [[ [ cond1 ] && [ cond2 ] ]]
    

    but have to use this:

    [[ cond1 ]] && [[ cond2 ]]
    

    or this:

    [[ cond1 && cond2 ]]
    

    with parentheses as required

  • Array element access has to look like this:

    ${BASH_REMATCH[1]}
    
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
-1

The problem turned out to be a typo on my part. I was using ~= instead of =~ as the regular expression operator and misinterpreted the diagnostics.

Jonathan
  • 2,635
  • 3
  • 30
  • 49
  • 1
    There's about half a dozen other problems, many of which are pointed out in Benjamin's answer. Probably try http://shellcheck.net/ before asking for human assistance. – tripleee Oct 16 '20 at 08:20