Sintaxe de declaração de substituição de comandos no bash - qual destes dois é melhor prática? [duplicado]

4
    

Esta pergunta já tem uma resposta aqui:

    

Isso faz parte de um loop bash find , e me perguntei qual é a sintaxe mais correta e por quê?

filename="$(echo "$i" | cut -c5-)";
filename='echo "$i" | cut -c5-';

Ambas funcionam com o objetivo de obter o nome do arquivo.

    
por Escher 01.08.2014 / 12:37

2 respostas

5

O manual do Bash observa que :

The POSIX $() form of command substitution is implemented (see Command Substitution), and preferred to the Bourne shell’s '' (which is also implemented for backwards compatibility).

Portanto, $(...) é preferido em relação a '...' em algo novo e específico para Bash que você esteja escrevendo¹. A substituição de Backtick não se encaixa bem (você precisa escapar deles) e tem um comportamento de cotação um pouco estranho. Você pode aninhar $(... $(...) ...) arbitrariamente sem problemas. O manual descreve o comportamento dos dois como :

When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by ‘$’, ‘'’, or ‘\’. The first backquote not preceded by a backslash terminates the command substitution. When using the $(command) form, all characters between the parentheses make up the command; none are treated specially.

É normalmente considerada a melhor prática para citar todas as expansões de strings para evitar problemas de divisão de palavras, inclusive em locais onde não é estritamente necessário, por isso "$(...)" também é uma prática melhor aqui.

Por fim, duas partes relevantes dessa mesma página de lã :

  • It's also time you forgot about '...'. It isn't consistent with the syntax of Expansion and is terribly hard to nest without a dose of painkillers. Use $(...) instead.
  • And for heaven's sake, "Use more quotes!" Protect your strings and parameter expansions from word splitting. Word splitting will eat your babies if you don't quote things properly.

¹ Na verdade, mesmo em scripts POSIX sh , estas são consideradas boas práticas. Ainda há bombas mais fracas por aí, mas você saberá se vai encontrá-las.

    
por 01.08.2014 / 12:43
5

Um comentário sobre boas práticas no seu código não está relacionado a '...' vs $(...) :

Em

filename="$(echo "$i" | cut -c5-)"

Existem pelo menos 4 advertências potenciais (pequenas, a menos que haja um incentivo para explorá-las):

  • Não é possível usar echo para dados arbitrários, pois você pode obter (dependendo do echo implementação ou ambiente) problemas com valores de $i que iniciam com - ou contêm barras invertidas. O melhor é usar printf (aqui printf '%s\n' "$i" ) ao lidar com dados arbitrários.
  • cut e a maioria dos utilitários de filtragem de texto não são muito apropriados para lidar com caminhos de arquivos porque eles agem em todas as linhas de suas entradas. Então, aqui, você está tirando os 4 primeiros caracteres da linha every de $i (a nova linha é tão válida quanto qualquer outro nome de arquivo). O melhor é usar filename=${i#????} (embora você também queira levar em conta casos em que $i contenha menos de 4 caracteres).
  • substituição de comando ( '...' ou $(...) ) remove todos caracteres de nova linha à direita da saída do comando. Então, se $i terminar em caracteres de nova linha, você sentirá falta deles em $filename . ${i#????} também trabalha em torno disso.
  • cut -c5- ou ${i#????} remove 4 caracteres . Tenha em atenção que, em algumas localidades, os caracteres podem ser constituídos por vários bytes . Você pode querer levar isso em conta. (também note que GNU cut não suporta caracteres multi-byte ainda ( cut -c é o mesmo que cut -b )).
por 01.08.2014 / 13:01