Curinga para caminho para localização no host remoto

1

No Bash eu preciso verificar se o caminho contido em uma string está apontando para um local remoto ou não. O seguinte não funciona - some code não é executado. Parece que estou perdendo alguma coisa sobre como os curingas funcionam com o comando test ( [ ), mas não consigo descobrir o que. A man page não me ajuda. O que estou fazendo de errado e como devo fazer isso?

path="user@host:/home/user"
if [ "$path" == ?*"@"?*":"?* ]; then
  some code
fi
    
por fuumind 09.08.2016 / 17:39

1 resposta

4

O comando [ é um comando e é analisado como qualquer outro comando. Isso significa que em:

[ "$path" == ?*"@"?*":"?* ]

O ?*"@"?*":"?* é considerado como glob e, portanto, expande para a lista de arquivos no diretório atual que corresponde a esse padrão (assim como *.txt expande para a lista de txt arquivos no diretório atual). / p>

Mesmo se você escreveu:

[ "$path" == '?*@?*:?*' ]

para impedir a globbing, que não funcionaria como o operador == (versão não padrão de = ) do comando [ é apenas um operador de igualdade de cadeia, não um padrão correspondente.

Para fazer a correspondência de padrões, você pode usar o operador de correspondência de padrões ksh -style [[ x = pattern ]] , que bash e zsh também suportam:

path="user@host:/home/user"
if [[ "$path" = ?*@?*:* ]]; then
  some code
fi

Ou, melhor ainda, use a construção POSIX / Bourne sh case :

case $path in
  ?*@?*:*) some code
esac

Dessa forma, você nem precisa ter o bash instalado, você pode usar o padrão do seu sistema sh para interpretar o seu script.

Observe que user@host:/home/user também é um caminho local válido (tente mkdir -p user@host:/home/user ), embora com scp seja necessário passá-lo como ./user@host:/home/user para que não seja tratado como um caminho remoto. Então você pode querer refinar seu teste para:

case ${path%%@?*:*} in
  (*/* | "$path" | "") echo not a remote path;;
  (*) echo remote path;;
esac

Para que ./x@y:z não seja tratado como um caminho remoto.

Ainda não é suficiente fazer o mesmo que scp faz para decidir se um caminho é remoto ou não. Olhando para OpenSSH scp code , um caminho é remoto se não Comece com : e se ele contiver um : sem / à esquerda dele e que não esteja dentro de [...] (para endereços IPv6 como [::1] . Exceto que esses [...] são apenas considerado na posição do host (no início ou após @ ) Assim, por exemplo x: , @: são caminhos remotos (embora obviamente a parte do usuário e do host esteja vazia, isso provavelmente não funcionará corretamente) e user@[::1/64]:/x ( / restante para o : que não está entre [...] ) ou [foo@bar:/path são caminhos locais (o : está dentro de [...] ).

A correspondência com uma instrução POSIX case seria impossível. Para corresponder a uma expressão regular, seria um pouco mais fácil com expressões regulares que suportam a pesquisa em torno de operadores como perl . zsh e ksh93 têm suporte para aqueles ( zsh usando a biblioteca PCRE, ksh93 usando sua própria implementação).

  • zsh :

    set -o rematchpcre
    remote='^(?!:)(?:(?!\[)[^/:]*@)?(?:\[(?:(?!]:)[^/])*\]|(?!\[)[^/:]*):'
    if [[ $path =~ $remote ]]; then
      some code
    fi
    
  • ksh93 :

    remote='(?P:^(?!:)(?:(?!\[)[^/:]*@)?(?:\[(?:(?!]:)[^/])*\]|(?!\[)[^/:]*):)'
    if [[ $path =~ $remote ]]; then
      some code
    fi
    

(Eu não ficaria surpreso se isso pudesse ser simplificado).

    
por 09.08.2016 / 17:50