Como posso testar se uma variável está vazia ou contém apenas espaços?

A seguinte sintaxe bash verifica se param não está “vazio:

 [[ ! -z $param ]] 

Por exemplo:

param="" [[ ! -z $param ]] && echo "I am not zero" 

Sem saída e está bom.

Mas quando param está vazio, exceto por um (ou mais) caracteres de espaço, então a caixa é diferente:

param=" " # one space [[ ! -z $param ]] && echo "I am not zero" 

“Não estou zero “é gerado.

Como posso alterar o teste para considerar as variáveis que contêm apenas caracteres de espaço como vazias?

Comentários

  • De man test: -z STRING - the length of STRING is zero. Se você deseja remover todos os espaços em $param, use ${param// /}
  • WOW , não há uma função trim() simples incorporada a qualquer * nix? Tantos hacks diferentes para conseguir algo tão simples …
  • @ADTC $ (sed ‘ s / ^ \ s + | \ s + $ // g ‘ < < < $ string) parece simples o suficiente para mim. Por que reinventar a roda?
  • Porque ela poderia ser mais brilhante
  • Apenas observando que [[ ! -z $param ]] é equivalente a test ! -z $param.

Resposta

Primeiro, observe que -z teste é explicitamente para:

o comprimento da string é zero

Ou seja, uma string contendo apenas espaços não seja verdadeiro em -z, porque tem um comprimento diferente de zero.

O que você quer é remover os espaços da variável usando o expansão do parâmetro de substituição de padrão :

[[ -z "${param// }" ]] 

Isso expande o param variável e substitui todas as correspondências do padrão (um único espaço) por nada, portanto, uma string que contém apenas espaços será expandida para um string vazia.


O essencial de como isso funciona é que ${var/pattern/string} substitui a primeira correspondência mais longa de pattern por string. Quando pattern começa com / (como acima) então ele substitui todas as correspondências. Como a substituição está vazia, podemos omitir o / e o string valor final:

$ {parâmetro / padrão / string}

O padrão é expandido para produzir um padrão, assim como na expansão do nome do arquivo. Parâmetro é expandido e a correspondência mais longa de padrão em relação a seu valor é substituída por string . Se padrão começar com ‘/’, todas as correspondências de padrão são substituídas por string . Normalmente, apenas a primeira correspondência é substituída. … Se string for nulo, as correspondências de padrão são excluídas e o / seguinte padrão pode ser omitido.

Depois de tudo isso, acabamos com ${param// } para excluir todos os espaços.

Observe que, embora presente em ksh (onde se originou), zsh e bash, essa sintaxe não é POSIX e não deve ser usado em sh scripts.

Comentários

  • use sed eles disseram … apenas echo a variável que eles disseram …
  • Hmm. Se for ${var/pattern/string}, então deve ‘ ser [[ -z ${param/ /} ]] com o espaço entre as barras ser o padrão e nada depois ser a string?
  • @JesseChisholm ” Como a substituição está vazia, podemos omitir o / final e o valor da string “; ” Se string for nulo, as correspondências de padrão são excluídas e o / seguinte padrão pode ser omitido. ”
  • @MichaelHomer A resposta [[ -z "${param// }" ]] com certeza se parece com pattern está vazio e replacement string é um único espaço. AH! Agora vejo if pattern begins with a slash Perdi essa parte. portanto, o padrão é / e a string é deixada de fora e, portanto, vazia. Obrigado.
  • nota bash: se executando em set -o nounset (set -u), e param não está definido (ao invés de nulo ou preenchido com espaço), então isso irá gerar um erro de variável não ligada. (set + u; …..) dispensaria esse teste.

Resposta

A maneira mais fácil verificar se uma string contém apenas caracteres em um conjunto autorizado é testar a presença de caracteres não autorizados.Portanto, em vez de testar se a string contém apenas espaços, teste se a string contém algum caractere diferente de espaço. Em bash, ksh ou zsh:

if [[ $param = *[!\ ]* ]]; then echo "\$param contains characters other than space" else echo "\$param consists of spaces only" fi 

“Consiste apenas em espaços” inclui o caso de uma variável vazia (ou não definida).

Você pode querer testar qualquer caractere de espaço em branco. Use [[ $param = *[^[:space:]]* ]] para usar as configurações de localidade ou qualquer lista explícita de caracteres de espaço em branco que você deseja testar, por exemplo, [[ $param = *[$" \t\n"]* ]] para testar se há espaço, tabulação ou nova linha.

Comparar uma string com um padrão com = dentro de [[ … ]] é uma extensão ksh (também presente em bash e zsh). Em qualquer estilo Bourne / POSIX, você pode usar a construção case para combinar uma string com um padrão. Observe que os padrões de shell padrão usam ! para negar um conjunto de caracteres, em vez de ^ como na maioria das sintaxes de expressão regular.

case "$param" in *[!\ ]*) echo "\$param contains characters other than space";; *) echo "\$param consists of spaces only";; esac 

Para testar os caracteres de espaço em branco, a sintaxe $"…" é específica para ksh / bash / zsh; você pode inserir esses caracteres em seu script literalmente (observe que uma nova linha terá que estar entre aspas, já que barra invertida + nova linha se expande para nada) ou gerá-los, por exemplo,

whitespace=$(printf "\n\t ") case "$param" in *[!$whitespace]*) echo "\$param contains non-whitespace characters";; *) echo "\$param consists of whitespace only";; esac 

Comentários

  • Isso é quase excelente – mas, por enquanto, não responde à pergunta conforme feita. Atualmente, ele pode dizer a você a diferença entre uma variável de shell não definida ou vazia e uma que contém apenas espaços. Se você aceitar minha sugestão, você adicionará a forma de expansão de param ainda não convertida por qualquer outra resposta que testa explicitamente uma variável shell para ser definida – quero dizer ${var?not set} – passando no teste e sobrevivendo garantiria que uma variável correspondida por seu *) case afetaria uma resposta definitiva, por exemplo.
  • Correção – isso, na verdade, responderia à pergunta feita originalmente, mas desde então foi editada de forma que muda fundamentalmente o significado da pergunta e, portanto, invalida sua resposta.
  • Você precisa de [[ $param = *[!\ ]* ]] em mksh.

Resposta

POSIXly:

case $var in (*[![:blank:]]*) echo "$var contains non blank";; (*) echo "$var contains only blanks or is empty or unset" esac 

Para diferenciar entre em branco , não em branco , vazio , não definido :

case ${var+x$var} in (x) echo empty;; ("") echo unset;; (x*[![:blank:]]*) echo non-blank;; (*) echo blank esac 

[:blank:] é para caracteres de espaçamento horizontal (espaço e tabulação em A SCII, mas provavelmente há mais alguns em sua localidade; alguns sistemas incluem o espaço ininterrupto (quando disponível), alguns não vão). Se você também quiser caracteres de espaçamento vertical (como nova linha ou alimentação de formulário), substitua [:blank:] com [:space:].

Comentários

  • POSIXly é ideal porque funcionará com (possivelmente melhor) traço.
  • zsh parece ter problemas com [![:blank:]], aumenta :b é um modificador inválido. Em sh e ksh emular, ele gera evento não encontrado para [
  • @cuonglm, o que você tentou? var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac' está OK para mim. O evento não encontrado seria apenas para shells interativos.
  • @St é phaneChazelas: Ah, certo, tentei com shells interativos. O :b modificador inválido é um pouco estranho.
  • @FranklinYu, no OS / X sh é construído com --enable-xpg-echo-default e --enable-strict-posix-default para ser compatível com Unix (o que envolve echo '\t' gerando uma guia).

Resposta

O único motivo restante para escrever um script de shell, em vez de um script em uma boa linguagem de script, se a portabilidade extrema for uma preocupação prioritária. O /bin/sh legado é a única coisa que você pode ter certeza de que possui, mas o Perl, por exemplo, tem mais probabilidade de estar disponível em várias plataformas do que o Bash. Portanto, nunca escreva scripts de shell que usem recursos que não sejam verdadeiramente universais – e tenha em mente que vários fornecedores Unix proprietários congelaram seu ambiente de shell antes de POSIX.1-2001 .

Existe uma maneira portátil de fazer este teste, mas você deve usar tr:

[ "x`printf "%s" "$var" | tr -d "$IFS"`" = x ] 

(O valor padrão de $IFS, convenientemente, é um espaço, uma guia e uma nova linha.)

(O printf builtin é em si mesmo perfeitamente portátil, mas confiar nele é muito menos trabalhoso do que descobrir qual variante de echo você tem.)

Comentários

  • Isso ‘ é um pouco complicado.A maneira portátil usual de testar se uma string contém certos caracteres é com case .
  • @Gilles eu não ‘ não acho ‘ possível escrever um case glob para detecta uma string que está vazia ou contém apenas caracteres de espaço em branco. (Seria fácil com uma regexp, mas case não ‘ não faz regexps. A construção em sua resposta ganhou ‘ t funciona se você se preocupa com novas linhas.)
  • Eu dei espaços como exemplo na minha resposta porque ‘ é a questão pediu. É ‘ igualmente fácil de testar para caracteres de espaço em branco: case $param in *[![:space:]]*) …. Se quiser testar IFS caracteres, você pode usar o padrão *[$IFS]*.
  • @mikeserv De fato sério script defensivo, você define explicitamente IFS como <space><tab><newline> no início e nunca mais o toca novamente. Achei que ‘ d fosse uma distração.
  • Com relação às variáveis em padrões, acho que funciona em todas as versões Bourne e em todos os shells POSIX; exigiria código extra para detectar padrões de caso e desligar a expansão de variável e não consigo ‘ não pensar em uma razão para fazer isso. Eu tenho algumas instâncias dele em meu .profile que foi executado por muitos shells Bourne. É claro que [$IFS] ganhou ‘ t fazer o que era pretendido se IFS tiver certos não padrão valores (vazios (ou não definidos), contendo ], começando com ! ou ^) .

Resposta

if [[ -n "${variable_name/[ ]*\n/}" ]] then #execute if the the variable is not empty and contains non space characters else #execute if the variable is empty or contains only spaces fi 

Comentários

  • isso elimina qualquer caractere de espaço em branco, não apenas um único espaço, certo? obrigado

Resposta

Para testar se a variável está vazia ou contém espaços, você também pode usar este código:

${name:?variable is empty} 

Comentários

  • Acho que sua resposta foi rejeitada porque ” ou conter espaços ” não é verdade.
  • tenha cuidado – isso mata o shell atual. Melhor colocá-lo em um (: $ {subshell?}). Além disso – isso escreverá para stderr – você provavelmente deseja redirecionar. E o mais importante que avalia o valor real da variável ‘ s se não for indefinido ou nulo. Se houver ‘ s um comando lá, basta executá-lo. É ‘ melhor executar esse teste em :.
  • como ele matará o shell. e você também pode testar isso, primeiro defina name=aaaa e execute este comando echo ${name:?variable is empty} ele imprimirá o valor do nome da variável e agora execute este comando echo ${name1:?variable is empty} ele imprimirá -sh: name1: variable is empty
  • Sim – echo ${name:?variable is empty} será avaliado como $name ‘ um valor não nulo ou matará o shell. Portanto, pela mesma razão, você não ‘ t faça prompt > $randomvar nem deve ${var?} – se há ‘ um comando lá, ele ‘ provavelmente será executado – e você não ‘ t sei o que é. Um shell interativo não ‘ tem que sair – é por isso que o seu não ‘ t. Ainda assim, se você quiser ver alguns testes, há muitos deles aqui. . Este não é ‘ tão longo …

Resposta

O código que você postou [[ ! -z $param ]] && echo "I am not zero" imprimirá I am not zero se param está indefinido / indefinido ou vazio (em bash, ksh e zsh).

Para também print if param contém apenas espaços (remova espaços), POSIXly (para uma gama mais ampla de shells):

 [ -z "${param#"${param%%[! ]*}"}" ] && echo "empty" 

Explicação:

  • Um ${param# … } remove um texto inicial.
  • Esse texto inicial é fornecido por: ${param%%[! ]*}
  • Que se expande para todos os espaços antes de qualquer sem espaço caractere, ou seja, todos os espaços à esquerda.

O resultado final de toda a expansão é que todos os espaços iniciais são removidos.

Este resultado expandido é testado se tiver comprimento 0.

  • Se o resultado estiver vazio, então a variável estava vazia ou
  • removendo os espaços iniciais esvaziou.

Portanto, se o teste for verdadeiro, a variável já estava vazia ou só tinha espaços dentro dela.


O conceito é fácil de estender para mais tipos de personagens. Para incluir também tabulações, coloque uma tabulação explícita dentro da expressão de colchetes:

 [ -z "${param#"${param%%[! ]*}"}" ] && echo "empty" 

ou use uma variável com os caracteres que você precisa remover:

 var=$" \t" # in ksh, bash, zsh [ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty" 

ou você pode usar alguma “expressão de classe de caractere” POSIX (espaço em branco significa espaço e tabulação):

 [ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty" 

Resposta

Para verificar se a variável tem apenas espaços, incluindo em uma variável multilinha , tente isto:

[[ $var = *[$" \t\n"]* ]] 

Ou com xargs:

[[ -z $(echo $var | xargs) ]] 

Ou com sed:

[[ -z $(sed "/^$/d" <<< $var) ]] 

Resposta

Tente isto:

$ [[ -z \`echo $n\` ]] && echo zero zero 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *