Como aninhar adequadamente os versos do Bash

92

Ou perdi alguma folga ou a reação não parece funcionar com muito looping de citações do programador.

$ echo "hello1-`echo hello2-\`echo hello3-\`echo hello4\`\``"

hello1-hello2-hello3-echo hello4

Procurado

hello1-hello2-hello3-hello4-hello5-hello6-...
hhh
fonte
A questão provavelmente deveria ser "Como usar backticks Bash recursivamente". Isso deve ajudar os Googlers por aí.
Joey Adams
o que você está tentando fazer.? isso não tem nenhum significado.
ghostdog74,
1
@joey, título alterado, sejam bem-vindos: D
Stormenet,
1
Opa, risque isso. Ele deve ser "Como aninho crases no bash?" . Eu tenho recursão e aninhamento misturados.
Joey Adams
Backticks são deprecated, portanto, use $(cmd).
Timo

Respostas:

145

Use em seu $(commands)lugar:

$ echo "hello1-$(echo hello2-$(echo hello3-$(echo hello4)))"
hello1-hello2-hello3-hello4

$(commands) faz a mesma coisa que crases, mas você pode aninhá-los.

Você também pode estar interessado nas expansões do intervalo Bash:

echo hello{1..10}
hello1 hello2 hello3 hello4 hello5 hello6 hello7 hello8 hello9 hello10
Joey Adams
fonte
+1 como o {1..10}. Limitar com array? ZSH pode "$ {$ (data) [2,4]}". Por que não: "echo $ {echo hello1 - $ (echo hello2) [1]}"?
hhh
35

se você insiste em usar crases, o seguinte pode ser feito

$ echo "hello1-`echo hello2-\`echo hello3-\\\`echo hello4\\\`\``"

tem que colocar barras invertidas, \\ \\\\ \\\\\\\\de 2x e assim por diante, é muito feio, use $(commands)como sugerido.

VOCÊS
fonte
11

Sempre que você quiser avaliar um comando, use command substitution:

$(command)

Sempre que quiser avaliar uma expressão aritmética, use expression substitution:

$((expr))

Você pode aninhar assim:

Digamos que file1.txt tenha 30 linhas e file2.txt tenha 10 linhas, então você pode avaliar uma expressão como esta:

$(( $(wc -l file1.txt) - $(wc -l file2.txt) ))

que produziria 20 (a diferença no número de linhas entre dois arquivos).

toobsco42
fonte
10

É muito mais fácil se você usar a $(cmd) sintaxe de substituição de comando do bash , que é muito mais fácil de ser aninhada:

$ echo "hello1-$(echo hello2-$(echo hello3-$(echo hello4)))"
hello1-hello2-hello3-hello4
Mark Rushakoff
fonte
5
Isso não está restrito a bash . Ele está disponível em todos os shells que estão em conformidade com POSIX 1003.1 (“shells POSIX”) e a maioria dos shell derivados de Bourne ( ksh , ash , dash , bash , zsh , etc.), embora não o shell Bourne real (ou seja, heirloom.sourceforge.net /sh.html ).
Chris Johnsen,
uau, o carimbo de data / hora nesta resposta é IDÊNTICO ao da resposta @joey_adams! Sincronização em seu significado mais literal :) Também aqui votando positivamente (:
drevicko
0

Às vezes, o aninhamento de crase pode ser substituído por xargse tubos

$ echo hello4 | xargs echo hello3 | xargs echo hello2 | xargs echo hello1
hello1 hello2 hello3 hello4

As desvantagens desta solução são:

  • Todos os argumentos devem ser fornecidos na ordem inversa (4 → 1);
  • Todos os argumentos se tornam separados por espaço (solucionável com tr):

    $ echo hello4 | xargs echo hello3 | xargs echo hello2 | xargs echo hello1 | tr ' ' '-'
    hello1-hello2-hello3-hello4


Vamos mostrar um caso de uso real.

Os comandos a seguir funcionam em bash, mas não em tcsh (aninhamento de crase não é muito bem tratado em tcsh)

$ ls $(dirname $(which bash))
$ ls `dirname \`which bash\``

Eles podem ser substituídos por

$ which bash | xargs dirname | xargs ls
GC
fonte