algalg
algalg

Reputation: 821

Bash: Regex: Matching if a string is a remote host for rsync

I thought I had a good regex line below that works with tests I did in Regexbuddy, but doesn't seem to work in bash.

I need someone with much better knowledge of regex than me to help me out. ;)

The point is to do a basic test as to whether a string contains a remote host for rsync. So we're testing for something valid like username@host:/ or username@host:~/ (and I also assume ./ ?) ...

#!/bin/bash

test="foo@bar:/here/path/"
regex='^([\w-_.]*)@([\w-_.:]*):[~./]'

if [[ "${test}" =~ "${regex}" ]]; then 
    echo "yes, remote host" 
else 
    echo "no, local"
fi

# filter for remote host by regex
# ^ begin at start of line, ( [ match underscore, word & number chars, dashes, fullstops ] in * repetition ) until first @ and then ( [ match underscore, word & number chars, dashes, fullstops, and colons] in * repetition ) until : and then at least [ ~ or . or / )
# so [email protected]:/path/ will match
# [email protected]:~/path/ will match
# blah123.user@2001:db8:85a3:8d3:1319:8a2e:370:7348:./path/ will match
# user@wherever:path/ will not, and /[email protected]:with/a/slash will not match
# etc

Any ideas?

Upvotes: 2

Views: 375

Answers (2)

ColOfAbRiX
ColOfAbRiX

Reputation: 1059

Bash doesn't support character classes like \w, have a look here https://tldp.org/LDP/abs/html/x17129.html section POSIX Character Classes

In your case try replacing \w with [:alnum:] and you have to remove the quotes on the right side of =~.

I modified it a bit but this works for me:

[[ "foo@bar:/here/path/" =~ ^[-_\.[:alnum:]]+@[-_\.[:alnum:]]+:[~./] ]] && \
    echo "Remote" || \
    echo "Local"

Upvotes: 1

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627103

There are several issues:

  • The $regex variable should not be quoted after =~, or non-regex string matching gets enabled
  • \w should not be used, use [:alnum:] POSIX character class instead, that matches letters and digits
  • - in bracket expressions should be the first or last character to be correctly parsed as a hyphen.

I'd also use + (1 or more) quantifier instead of * in the pattern to enforce at least one char before and after @.

You can use

test="foo@bar:/here/path/"
regex='^([[:alnum:]_.-]+)@([[:alnum:]_.:-]+):[~./]'
if [[ "$test" =~ $regex ]]; then 
    echo "yes, remote host" 
else 
    echo "no, local"
fi

See Bash demo.

Upvotes: 4

Related Questions