Como adicionar novas linhas em variáveis ​​no script bash

64

Quando eu faço

str="Hello World\n===========\n"

Também recebo a \nimpressão. Como posso ter novas linhas então?

Jiew Meng
fonte
11
Embora as respostas aqui sejam ótimas, na realidade acho que seria melhor usar uma matriz para esse tipo de coisa na maioria das vezes.
evilsoup
Consulte também a pergunta Tentando incorporar nova linha em uma variável no bash .
HelloGoodbye

Respostas:

73

Em bashvocê pode usar a sintaxe

str=$'Hello World\n===========\n'

Aspas simples precedidas por a $são uma nova sintaxe que permite inserir seqüências de escape em strings.

Também printfembutido permite salvar a saída resultante em uma variável

printf -v str 'Hello World\n===========\n'

Ambas as soluções não requerem um subshell.

Se você precisar imprimir a sequência a seguir, use aspas duplas, como no exemplo a seguir:

echo "$str"

porque quando você imprime a sequência sem aspas, a nova linha é convertida em espaços.

enzotib
fonte
11
Como é str=$'Hello World\n===========\n'chamada a sintaxe ? substituição de variável?
Zengr 10/08/13
5
@zengr: É chamado de citação ANSI-C , e também é suportado em zshe ksh; no entanto, NÃO é compatível com POSIX.
precisa saber é o seguinte
4
@ mkelement0, vem de ksh93, também é suportado pelo zsh, festança, mksh e sh FreeBSD, e sua inclusão na próxima grande revisão do POSIX é em discussão
Stéphane Chazelas
11
Não parece funcionar com aspas duplas? por exemplo str=$"My $PET eats:\n$PET food"? Esta abordagem funciona para aspas duplas
Brad Parks
31

Você pode colocar novas linhas literais entre aspas simples (em qualquer shell no estilo Bourne / POSIX).

str='Hello World
===========
'

Para uma sequência de múltiplas linhas, aqui os documentos geralmente são convenientes. A cadeia é alimentada como entrada para um comando.

mycommand <<'EOF'
Hello World
===========
EOF

Se você deseja armazenar a sequência em uma variável, use o catcomando em uma substituição de comando. O (s) caractere (s) de nova linha no final da cadeia de caracteres será removido pela substituição do comando. Se você deseja manter as novas linhas finais, coloque uma tampa no final e retire-a depois. Em shells compatíveis com POSIX, você pode escrever str=$(cat <<'EOF'); str=${str%a}seguido pelo heredoc propriamente dito, mas o bash exige que o heredoc apareça antes do parêntese de fechamento.

str=$(cat <<'EOF'
Hello World
===========
a
EOF
); str=${str%a}

No ksh, bash e zsh, você pode usar o $'…'formulário entre aspas para expandir escapes de barra invertida dentro das aspas.

str=$'Hello World\n===========\n'
Gilles 'SO- parar de ser mau'
fonte
11
Estou usando o GNU bash 4.1.5 e str=$(cat <<'EOF')não funciona como está. As )necessidades devem ser colocadas na próxima linha após o final do documento EOF.. mas, mesmo assim, ele perde a nova linha à direita devido ao comando Substituição.
precisa saber é o seguinte
@ fred Bons pontos, expliquei sobre as novas linhas à direita e mostrei o código que funciona no bash. Eu acho que é um bug no bash, embora, para ser honesto, ao reler a especificação POSIX, não seja claro que o comportamento seja obrigatório quando o << estiver dentro de uma substituição de comando e o heredoc não.
Gilles 'SO- stop be evil'
Coisas boas; para preservar as \ninstâncias finais (e principais) bashao capturar um documento aqui em uma variável, considere IFS= read -r -d '' str <<'EOF'...como uma alternativa à abordagem de interrupção (veja minha resposta).
precisa saber é o seguinte
8

Você está usando "eco"? Tente "eco-e".

echo -e "Hello World\n===========\n"
Mike
fonte
2
Entre. Você não precisa do final \ n, porque echoele adicionará automaticamente um, a menos que você especifique -n. (No entanto, o principal problema da questão é como obter essas novas linhas em uma variável).
precisa saber é o seguinte
+1 De todas as soluções, esta é a mais direta e mais simples.
Hai Vu
echo -e não funciona no OS X
Greg M. Krsak 04/04
2
@GregKrsak: In bash, echo -e faz o trabalho no OS X - que é porque echoé uma festa builtin (em vez de um executável externo) e que builtin suporta -e. (Como um builtin, ele deve funcionar em todas as plataformas que o bash é executado em, aliás, echo -etrabalha em kshe zshtambém). Por outro lado, no entanto, o utilitário externoecho no OS X - /bin/echo- na verdade não suporta -e.
usar o seguinte comando
4

Se você precisar de novas linhas em seu script muitas vezes, poderá declarar uma variável global que contém uma nova linha. Dessa forma, você pode usá-lo em cadeias de citação dupla (expansões variáveis).

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"
pihentagy
fonte
Por que $''exigiria um subshell?
Mat
Desculpe, eu li mal uma resposta.
pihentagy
Eu poderia pedir explicações aos que recusaram?
precisa saber é o seguinte
Agradável! Isso pode ser incluído em variáveis ​​usando aspas duplas, por exemplo"My dog eats:${NL}dog food"
Brad Parks
Isso funcionou para mim. Ao usar um script bash para compor uma sequência que é automaticamente copiada na área de transferência para colar posteriormente em outro lugar, essa abordagem funcionou para adicionar novas linhas na saída resultante.
Ville
3

De todas as discussões, aqui está a maneira mais simples para mim:

bash$ str="Hello World
==========="
bash$ echo "$str"
Hello World
===========

O comando echo deve usar aspas duplas .

kholis
fonte
3

Para complementar as ótimas respostas existentes:

Se você estiver usando bashe preferir usar novas linhas reais para facilitar a leitura , readé outra opção para capturar um documento aqui em uma variável , que (como outras soluções aqui) não requer o uso de um subshell.

# Reads a here-doc, trimming leading and trailing whitespace.
# Use `IFS= read ...` to preserve it (the trailing \n, here).
read -r -d '' str <<'EOF'   # Use `IFS= read ...` to preserve the trailing \n
Hello World
===========
EOF
# Test: output the variable enclosed in "[...]", to show the value's boundaries.
$ echo "$str"
[Hello World
===========]
  • -rgarante que readnão interprete a entrada (por padrão, trataria barras invertidas especiais, mas isso raramente é necessário).

  • -d ''define o delimitador "record" como uma string vazia, fazendo readcom que leia toda a entrada de uma só vez (em vez de apenas uma única linha).

Observe que, deixando $IFS(o separador de campo interno) em seu padrão $' \t\n'(um espaço, uma guia, uma nova linha), qualquer espaço em branco à esquerda e à direita é aparado a partir do valor atribuído a $str, que inclui a nova linha à direita do documento.
(Observe que, embora o corpo do documento aqui inicie na linha após o delimitador de início ( 'EOF'aqui), ele não contém uma nova linha principal ).

Geralmente, esse é o comportamento desejado, mas se você deseja essa nova linha à direita, use em IFS= read -r -d ''vez de apenas read -r -d '', mas observe que qualquer espaço em branco à esquerda e à direita é preservado.
(Observe que anexar IFS= diretamente ao readcomando significa que a atribuição está em vigor apenas durante esse comando, portanto, não há necessidade de restaurar o valor anterior.)


O uso de um documento aqui também permite que você use opcionalmente o recuo para ativar a cadeia de linhas múltiplas para facilitar a leitura:

# Caveat: indentation must be actual *tab* characters - spaces won't work.
read -r -d '' str <<-'EOF' # NOTE: Only works if the indentation uses actual tab (\t) chars.
    Hello World
    ===========
EOF
# Output the variable enclosed in "[...]", to show the value's boundaries.
# Note how the leading tabs were stripped.
$ echo "$str"
[Hello World
===========]

A colocação -entre <<e o delimitador here-doc de abertura ( 'EOF', aqui) faz com que os caracteres de tabulação iniciais sejam retirados do corpo do doc here e até do delimitador de fechamento, mas observe que isso só funciona com caracteres de tabulação reais , não espaços, por isso, se você editor converte pressionamentos de tecla da guia em espaços, é necessário trabalho extra.

mklement0
fonte
-1

você precisa fazer assim:

STR=$(echo -ne "Hello World\n===========\n")

Atualizar:

Como Fred apontou, dessa maneira você perderá o "\ n" final. Para atribuir variáveis ​​com as seqüências de barra invertida expandidas, faça:

STR=$'Hello World\n===========\n\n'

vamos testá-lo:

echo "[[$STR]]"

nos dá agora:

[[Hello World
===========

]]

Observe que $ '' é diferente de $ "". O segundo faz a tradução de acordo com a localidade atual. Para oital, consulte a seção CITAÇÕES em man bash.

Michał Šrajer
fonte
-2
#!/bin/bash

result=""

foo="FOO"
bar="BAR"

result+=$(printf '%s' "$foo")$'\n'
result+=$(printf '%s' "$bar")$'\n'

echo "$result"
printf '%s' "$result"

resultado:

FOO
BAR

FOO
BAR
vern
fonte
11
Por que não simplesmente result+=$foo$'\n'? $(printf %s "$foo")apararia os caracteres de nova linha à direita, $foose houver.
Stéphane Chazelas 26/09/16
Não há explicação para o código; caso contrário, parece bom para mim.
somethingSomething