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 atest ! -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
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 = *[!\ ]* ]]
emmksh
.
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. Emsh
eksh
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 envolveecho '\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, mascase
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 testarIFS
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 seIFS
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 comandoecho ${name:?variable is empty}
ele imprimirá o valor do nome da variável e agora execute este comandoecho ${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çaprompt > $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
sed
eles disseram … apenasecho
a variável que eles disseram …${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?[[ -z "${param// }" ]]
com certeza se parece compattern
está vazio ereplacement string
é um único espaço. AH! Agora vejoif pattern begins with a slash
Perdi essa parte. portanto, o padrão é/
e a string é deixada de fora e, portanto, vazia. Obrigado.