Eu tenho uma string contendo muitas palavras com pelo menos um espaço entre cada dois. Como posso dividir a sequência em palavras individuais para que eu possa fazer um loop através delas?
A cadeia é passada como argumento. Por exemplo ${2} == "cat cat file"
. Como posso percorrer isso?
Além disso, como posso verificar se uma string contém espaços?
Respostas:
Você tentou passar a variável string para um
for
loop? O Bash, por exemplo, será dividido automaticamente em espaço em branco.fonte
A=${A}${word})
.touch NOPE; var='* a *'; for a in $var; do echo "[$a]"; done
saídas em[NOPE] [a] [NOPE]
vez do esperado[*] [a] [*]
(LFs substituídos pelo SPC para facilitar a leitura).Eu gosto da conversão para uma matriz, para poder acessar elementos individuais:
agora você pode acessar elementos individuais diretamente (começa com 0):
ou converta novamente em string para fazer um loop:
É claro que o loop direto da string foi respondido anteriormente, mas essa resposta teve a desvantagem de não acompanhar os elementos individuais para uso posterior:
Consulte também Referência do array bash .
fonte
touch NOPE; var='* a *'; arr=($var); set | grep ^arr=
saídasarr=([0]="NOPE" [1]="a" [2]="NOPE")
em vez do esperadoarr=([0]="*" [1]="a" [2]="*")
Basta usar as conchas "set" embutidas. Por exemplo,
Depois disso, palavras individuais em $ text estarão em $ 1, $ 2, $ 3, etc. Para maior robustez, geralmente
para lidar com o caso em que $ text esteja vazio ou comece com um traço. Por exemplo:
Isso imprime
fonte
awk
masset
é muito mais fácil. Agora sou umset
fanboy. Obrigado @Idelic!touch NOPE; var='* a *'; set -- $var; for a; do echo "[$a]"; done
saídas em[NOPE] [a] [NOPE]
vez do esperado[*] [a] [*]
. Use-o apenas se tiver 101% de certeza de que não há metacaracteres SHELL na string dividida!set -f
antesset -- $var
eset +f
depois desativar o globbing.set -f
sua solução também é seguro. Masset +f
é o padrão de cada shell, por isso é um detalhe essencial, que deve ser observado, porque outros provavelmente não o conhecem (como eu também).A maneira provavelmente mais fácil e segura no BASH 3 e acima é:
(onde
arr
é a matriz que pega as partes divididas da sequência) ou, se houver novas linhas na entrada e você desejar mais do que apenas a primeira linha:(observe o espaço
-d ''
, ele não pode ser deixado de fora), mas isso pode fornecer uma nova linha inesperada de<<<"$var"
(como isso implicitamente adiciona um LF no final).Exemplo:
Produz o esperado
como esta solução (em contraste com todas as soluções anteriores aqui) não é propensa a globbing inesperado e muitas vezes incontrolável do shell.
Além disso, isso fornece todo o poder do IFS, como você provavelmente deseja:
Exemplo:
Produz algo como:
Como você pode ver, os espaços também podem ser preservados dessa maneira:
saídas
Observe que a manipulação
IFS
no BASH é um assunto por si só, assim como seus testes, alguns tópicos interessantes sobre isso:unset IFS
: Ignora execuções de SPC, TAB, NL e on-line inicia e terminaIFS=''
: Sem separação de campos, apenas lê tudoIFS=' '
: Executa o SPC (e somente o SPC)Algum último exemplo
saídas
enquanto
saídas
BTW:
Se você não está acostumado a
$'ANSI-ESCAPED-STRING'
se acostumar com isso, economiza tempo.Se você não incluir
-r
(como emread -a arr <<<"$var"
), a leitura será escapada pela barra invertida. Isso é deixado como exercício para o leitor.Para a segunda pergunta:
Para testar algo em uma string em que costumo me ater
case
, já que isso pode verificar vários casos de uma só vez (nota: case apenas executa a primeira correspondência, se você precisar de instruções de uso de multiplicaçãocase
), e essa necessidade costuma ser o caso (trocadilho pretendido):Portanto, você pode definir o valor de retorno para verificar o SPC assim:
Por que
case
? Como geralmente é um pouco mais legível que as sequências de expressões regulares, e graças aos metacaracteres da Shell, ele lida com 99% de todas as necessidades muito bem.fonte
set -f
ouset -o noglob
alternar entre globbing, de modo que os metacaracteres do shell não causem mais danos nesse contexto. Mas eu realmente não sou amigo disso, pois isso deixa muito poder do shell / é muito propenso a erros para alternar essa configuração.;&
conseguir isso. Não tenho muita certeza de qual versão do bash apareceu. Eu sou um usuário 4.3;&
é o avanço forçado sem verificação de padrão, como em C. E também existe o;;&
que continua a fazer as verificações adicionais de padrão. Assim;;
é comoif ..; then ..; else if ..
e;;&
é comoif ..; then ..; fi; if ..
, onde;&
é comom=false; if ..; then ..; m=:; fi; if $m || ..; then ..
- nunca se para de aprender (dos outros););;&
antes de você comentar: D Obrigado, e que a concha esteja com você;) #Para verificar espaços, use grep:
fonte
echo "X" |
geralmente pode ser substituído por<<<"X"
, como este:grep -s " " <<<"This contains SPC"
. Você pode identificar a diferença se fizer algo semelhanteecho X | read var
ao contrárioread var <<< X
. Somente o último importa variávelvar
para o shell atual, enquanto para acessá-lo na primeira variante você deve agrupar assim:echo X | { read var; handle "$var"; }
(A) Para dividir uma frase em suas palavras (separadas por espaço), você pode simplesmente usar o IFS padrão usando
Exemplo executando o seguinte trecho
irá produzir
Como você pode ver, você pode usar aspas simples ou duplas também sem problemas.
Notas:
- isso é basicamente o mesmo da resposta do mob , mas dessa forma você armazena o array para qualquer necessidade adicional. Se você precisar apenas de um loop único, poderá usar a resposta dele, que é uma linha mais curta :)
- consulte esta pergunta para métodos alternativos para dividir uma string com base no delimitador.
(B) Para procurar um caractere em uma string, você também pode usar uma correspondência de expressão regular.
Exemplo para verificar a presença de um caractere de espaço que você pode usar:
fonte
Para verificar espaços apenas com o bash:
fonte
Isso gera cada palavra; você pode processar essa lista como desejar depois.
fonte