Em alguns casos, o número de espaços é importante nos scripts bash (ou outro shell)

14

Foi-me dito que os espaços são importantes em bashou outros scripts de shell e não devo alterar a existência de espaços, a menos que saiba o que estou fazendo. "Mudando a existência", quero dizer inserir um espaço entre dois caracteres não espaciais ou remover um espaço entre dois caracteres não espaciais, por exemplo, mudar var="$val"para var ="$val"ou vice-versa. Eu quero perguntar

Existem casos em que o uso de um único espaço ou o uso de vários espaços consecutivos em um script de shell faz a diferença? .

(Obviamente, inserir / excluir um espaço entre aspas faz a diferença, como mudar de echo "a b"para echo "a b"ou vice-versa. Estou procurando outros exemplos além deste exemplo trivial.)

Eu me deparei com essa pergunta, mas essa é sobre adicionar e remover espaços entre dois caracteres não espaciais, para os quais conheço muitos exemplos de que isso faria diferença.

Qualquer ajuda seria apreciada. Inclua mais variedades de conchas, se possível.

Weijun Zhou
fonte

Respostas:

19

Fora das aspas, o shell usa espaço em branco (espaços, guias, nova linha, retorno de carro, etc.) como um separador de palavras / tokens. Que significa:

  • Coisas não separadas por espaço em branco são consideradas uma "palavra".
  • Coisas separadas por um ou mais caracteres de espaço em branco são consideradas duas (ou mais) palavras.

O número real de caracteres de espaço em branco entre cada "coisa" não importa, desde que haja pelo menos um.

cas
fonte
Obrigado. Não consigo encontrar nenhum exemplo contrário. Eu só quero ter certeza.
Weijun Zhou
2
O Bash também considera espaços de formulário e feeds verticais.
fpmurphy
verdade. eu originalmente escrevi '... newlines, etc' e então mudei para adicionar explicitamente retornos de carro. acidentalmente caiu o 'etc'.
cas
E se o número de espaços for tão grande, que o programa não possa caber na memória?
Worse_Username
7
@Worse_Username O espaço em branco não precisa caber na memória. Acabei de criar um script de 48 GB em uma máquina com 8 GB de RAM e 20 GB de swap. Funcionou muito bem. Demorou 3 minutos para analisar todo esse espaço em branco, mas no final ele executou com êxito um echocomando com esse espaço em branco entre o comando e o argumento.
kasperd
23

Provavelmente isso é trapaça, mas é o seguinte:

rm foo\ bar         # "delete the file named 'foo bar'"

é diferente disso:

rm foo\  bar        # "delete the files named 'foo ' and 'bar'"

mesmo que os espaços não estejam entre aspas. ;-)

Mais confuso, isso:

rm \
    foo          # "delete the file named 'foo'"

é diferente disso:

rm \ 
    foo          # "delete the file named ' ', then run the command 'foo'"

mesmo que pareçam idênticos!

ruakh
fonte
Mesmo que os espaços não estejam entre aspas, a barra invertida é funcionalmente semelhante à forma de citação e eu colocaria isso na mesma categoria que o "exemplo trivial" da pergunta. (Ele é, porém interessante.)
David Z
12

Se não falar sobre o carácter de espaço ( U+0020), mas qualquer espaço em branco ( U+0020, \n, \t, etc.), então um caso particular vêm à minha mente: aqui, Documentos.

Este código (usando espaços):

cat <<- 'EOF'
<space><space>foo
EOF

Irá imprimir:

  foo

Mas este código (usando guias):

cat <<- 'EOF'
<tab><tab>foo
EOF

Irá imprimir:

foo

Isso ocorre porque ( como afirma o POSIX ):

Se o operador de redirecionamento for <<-, todos os caracteres <tab> iniciais serão retirados das linhas de entrada e da linha que contém o delimitador à direita.

nxnev
fonte
1
Isso é interessante. Pensei nos documentos aqui, mas não conhecia o <<-operador. Muito obrigado.
Weijun Zhou
aqui os documentos são uma forma de texto citado, não um código shell. a divisão de palavras do shell não se aplica.
cas
2

Isso também tem efeito ao escrever declarações de atribuição. Como se eu dissesse FOO=xyzque criaria uma variável de ambiente nomeada FOOcom valor xyz, mas se eu separar os iguais com um espaço, pensará que estou invocando um programa nomeado FOOcom o argumento =xyz. Por isso, importa quando se trata de certa sintaxe.

HSchmale
fonte
Geralmente FOO=xyz, cria uma variável interna do shell, mas não uma variável de ambiente. Você precisa set -aou export FOO=xyzpara isso (ou seja, torná-lo parte do ambiente de subprocessos que não são do subshell).
Hauke ​​Laging