O problema:
- Preciso atribuir a uma variável um valor decentemente longo.
- Todas as linhas do meu script devem estar sob um certo número de colunas.
Então, eu estou tentando atribuí-lo usando mais de uma linha.
É simples fazer sem recuos:
VAR="This displays without \
any issues."
echo "${VAR}"
Resultado:
This displays without any issues.
No entanto, com recuos:
VAR="This displays with \
extra spaces."
echo "${VAR}"
Resultado:
This displays with extra spaces.
Como posso atribuí-lo elegantemente sem esses espaços?
$IFS
são uma ferramenta poderosa e universal - mas o código escrito dessa maneira nunca pode produzir resultados confiáveis de qualquer tipo.*
?
[]
).As soluções dadas por esuoxu e Mickaël Bucas são as maneiras mais comuns e portáteis de fazer isso.
Aqui estão algumas
bash
soluções (algumas das quais também devem funcionar em outras conchas, comozsh
). Primeiramente, com o+=
operador append (que funciona de uma maneira ligeiramente diferente para cada uma de uma variável inteira, uma variável regular e uma matriz).Se você deseja novas linhas (ou outros espaços em branco / escapes) no texto, use
$''
aspas:Em seguida, use
printf -v
para atribuir um valor formatado a uma variávelO truque aqui é que existem mais argumentos do que especificadores de formato; portanto, ao contrário da maioria das
printf
funções, o bash reutiliza a sequência de formatação até que ela se esgote. Você pode colocar um\n
dentro da string de formato ou usar $ '', (ou ambos) para lidar com espaços em branco.Em seguida, usando uma matriz:
Você também pode usar
+=
para criar o texto linha por linha (observe o()
):Aqui, porém, você deve se lembrar de "achatar" a matriz se quiser todo o conteúdo de texto de uma só vez
(matrizes indexadas por número inteiro são classificadas implicitamente, ao contrário de matrizes associativas) Isso oferece um pouco mais de flexibilidade, pois você pode manipular linhas e até fatiar e cortar dados, se necessário.
Por fim, usando
read
orreadarray
e um "documento aqui":A forma de documento aqui
<<-
significa que todas as guias físicas principais são removidas da entrada; portanto, você deve usar as guias para recuar o texto. As aspas"EOT"
impedem os recursos de expansão do shell; portanto, a entrada é usada literalmente. Comread
ele, usa entrada NUL delimitada por bytes, para que ele leia o texto delimitado por nova linha de uma só vez. Comreadarray
(akamapfile
, disponível desde o bash-4.0), ele lê em uma matriz e-t
retira novas linhas em cada linha.fonte
read
opção comhere document
é muito boa! Útil para incorporar scripts python e executar compython -c
. Eu costumava fazerscript=$(cat <here document>)
antes, masread -r -d '' script <here document>
é muito melhor.Existe uma sintaxe heredoc especial que remove as guias no início de todas as linhas: "<< -" (observe o traço adicionado)
http://tldp.org/LDP/abs/html/here-docs.html
Exemplo 19-4. Mensagem de várias linhas, com abas suprimidas
Você pode usá-lo assim:
Resultado:
Funciona apenas com guias, não espaços.
fonte
\t
funciona muito bem se você precisar de guias. Basta usarecho -e "$v"
ao invésecho "$v"
de habilitar caracteres de barra invertidaDeixe a casca comer as linhas indesejadas e os seguintes espaços:
Portanto, é possível ... mas com certeza é uma questão de gosto gostar ou não dessa solução ...
fonte
Talvez você possa tentar isso.
fonte
É assim que eu sugiro que você faça, e vou explicar o porquê, mas primeiro quero falar sobre outra coisa ...
Muitas das outras soluções oferecidas aqui parecem sugerir que você pode, de alguma forma, afetar o conteúdo de uma variável de shell alterando seus métodos de expansão. Posso garantir que esse não é o caso.
RESULTADO
O que você vê acima é primeiro uma expansão de divisão de campo, depois um relatório sobre a contagem de bytes para a variável de origem da expansão, depois uma expansão delimitada por aspas e a mesma contagem de bytes. Embora a saída possa diferir, o conteúdo da variável do shell
$string
nunca muda, exceto na atribuição.Além do mais, se você não entende por que isso ocorre, é provável que encontre surpresas muito desagradáveis, mais cedo ou mais tarde. Vamos tentar novamente, mas em condições ligeiramente diferentes.
Mesmo
$string
- ambiente diferente.RESULTADO
A divisão de campo ocorre com base nos delimitadores de campo definidos em
$IFS
. Existem dois tipos de delimitadores -$IFS
espaço em branco e$IFS
qualquer outra coisa. Por padrão,$IFS
é atribuída a nova linha da guia do espaço de valor - que são os três$IFS
valores possíveis de espaço em branco. Porém, é facilmente alterado, como você pode ver acima, e pode ter efeitos drásticos nas expansões divididas em campo.$IFS
o espaço em branco será eliminado por sequência em um único campo - e é por isso queecho
uma expansão contendo qualquer sequência de espaços quando$IFS
contiver um espaço será avaliada em apenas um espaço - porqueecho
concatena seus argumentos em espaços. Mas quaisquer valores que não sejam de espaço em branco não serão exibidos da mesma maneira, e cada delimitador sempre terá um campo em si - como pode ser visto na expansão de coisas acima.Isso não é o pior. Considere esse outro
$string
.RESULTADO
Parece ok, certo? Bem, vamos alterar o ambiente novamente.
RESULTADO
Woah.
Por padrão, o shell expandirá os globs do nome do arquivo, se puder correspondê-los. Isso ocorre após a expansão do parâmetro e a divisão do campo em sua ordem de análise e, portanto, qualquer string não citada fica vulnerável dessa maneira. Você pode desativar esse comportamento
set -f
se quiser, mas qualquer shell compatível com POSIX sempre será exibido por padrão.Esse é o tipo de coisa contra a qual você solta citações em expansões para se adequar às suas preferências de recuo. E mesmo assim, em todos os casos, independentemente do seu comportamento de expansão, o valor real
$string
ainda é sempre o que era quando você o atribuiu pela última vez. Então, voltemos à primeira coisa.RESULTADO
Acredito que esta é uma maneira muito mais sadia de adaptar a sintaxe do shell às suas preferências de recuo. O que estou fazendo acima é atribuir cada sequência individual a um parâmetro posicional - que pode ser referenciado por número como
$1
ou${33}
- e depois atribuir seus valores concatenados ao$var
uso do parâmetro shell especial$*
.Essa abordagem não é imune
$IFS
, mesmo assim. Ainda assim, considero sua relação com$IFS
um benefício adicional a esse respeito. Considerar:RESULTADO
Como você pode ver,
$*
concatena cada argumento no"$@"
primeiro byte$IFS
. Assim, salvar seu valor enquanto$IFS
é atribuído de forma diferente obtém delimitadores de campo diferentes para cada valor salvo. O que você vê acima é o valor literal de cada variável, a propósito. Se você não quisesse delimitador, faria:RESULTADO
fonte
Você pode tentar:
ou
e você também pode verificar isso .
fonte
Use uma expansão de substituição de bash
Se você estiver usando o Bash, poderá usar uma expansão de substituição . Por exemplo:
fonte
Esta é uma variante para definir variáveis semelhantes a caminhos:
Usando
set
substituições$@
, que podem ser salvas e usadas posteriormente, da seguinte maneira:A
LD_LIBRARY_PATH=$(sed 's/ :/:/g' <<< $LD_LIBRARY_PATH)
linha elimina espaços antes de dois pontos, bem como possíveis espaços em branco à direita. Se apenas eliminar espaços finais, use-oLD_LIBRARY_PATH=${LD_LIBRARY_PATH%% }
.Toda essa abordagem é uma variante da excelente resposta do mikeserv.
fonte
Não tenha medo de caracteres em branco. Basta removê-los antes de imprimir o texto de várias linhas.
Resultado:
Não há necessidade de usar um
<<-
heredoc e interromper seu recuo de 4 espaços com caracteres de tabulação.fonte