Pipes & precedência de ligação de redirecionamento com disjunts, conjuntos etc?

6

Conheço a precedência de ligação relativa dos operadores ";", "&", "& &" ou "||"

link

mas quando os canos entram na foto junto com "& &" Eu luto para entender a força de ligação e ou tropeço em um comando correto ou simplesmente desisto.

Qual é a precedência de ligação de '|' e '>' comparado ao acima?

Exemplo onde me confundo:

ls _thumbnails/video.mp4.jpg 2>/dev/null 
    && echo "thumbnail already generated. Not regenerating" \
    && exit \
    || ffmpeg_thumbnail_create video.mp4 2>/dev/null \
    && ls _thumbnails/video.mp4.jpg \
    && echo "Thumbnail successfully created" \
    && exit \
    || echo "Thumbnail creation failed" \
    | tee ~/thumbnails.log

O objetivo acima é criar uma miniatura se, e somente se, alguém ainda não estiver presente (eu executo um cronjob diário). E eu não gosto da quantidade enorme de saída do ffmpeg quando não há erro (o que não é o jeito Unix). Existem outras situações também, portanto, não comece a me dar conselhos que usem declarações separadas ou opções especiais específicas desses programas. Eu quero entender a precedência de ligação.

    
por user7000 22.10.2014 / 00:38

1 resposta

8

A resposta curta é que < , > e suas variantes tem a maior precedência de ligação (ligação mais estreita), seguido por | , seguido por && e || , seguido por ; e & . Portanto, somente o echo "Thumbnail creation failed" é canalizado para o tee .

Uma resposta um pouco mais longa indicaria que a precedência mais alta está realmente agrupando, o que pode ser indicado com parênteses ou chaves. Por exemplo,

A  &&  (B; C)

e

A  &&  { B; C;}

são aproximadamente equivalentes a

if A
then
    B
    C
fi

Notas:

  • Os parênteses dão uma subchave; isto é, os comandos B e C são executados em um processo filho. Assim sendo, comandos como atribuições de variáveis ou cd não terá efeito no shell pai. Os comandos entre chaves são executados no mesmo processo que o comando A . Portanto, a construção da chave A && { B; C;} está mais próxima da construção if - then - else .
  • Na sintaxe de chave, deve ser um espaço depois de { e ; (ou & ou newline) antes do } .

Para ler mais, consulte Quais são os operadores de controle e redirecionamento do shell? e Quando é 'se' não é necessário? (particularmente minhas respostas).

Para ainda mais ler mais, veja o bash (1) página de manual e a especificação POSIX / definição da Linguagem de Comandos Shell , especificamente Seção 2.9, Comandos da Shell e Seção 2.10.2, Regras gramaticais de shell . Esta é uma tentativa de fornecer algum contexto para o acima:

  • Coisas como

    • myVar=42
    • IFS= read a
    • date
    • cd /some/directory
    • ls -laR dir1 dir2
    • cat foo* > /tmp/allfoo
    • ls -laR dir{1,2}
    • find . -type f -name "foo*" -print > /tmp/output 2> /dev/null
    • > newfile
    • [ -f catfood ]
    • exit

    são todos considerados "comandos simples".

  • Coisas como
    simple_command1  |  simple_command2  |  simple_command3
são "pipelines". A gramática estabelece blocos de construção e constrói sobre eles, como é típico de gramáticas formais como esta (e para linguagens de programação como C), então um “comando simples” individual é considerado um “pipeline”, mesmo que não contenha um pipe. Não faz sentido (semântico) para uma atribuição de variável ser um componente de um pipeline, mas coisas como x=1 | od -ab ou ls -laR | z=0 são sintaticamente válidas.
  • Coisas como
    pipeline1  &&  pipeline2  ||  pipeline3
    são chamados de “listas” por bash e “listas AND-OR” por POSIX. Mais uma vez, um “pipeline” individual ou até mesmo um “comando simples” individual é considerado uma “lista AND-OR”, mesmo que não contenha um AND ou um OR.
  • Quando você chega a coisas como
    AND-OR list1 &  AND-OR list2 ;  AND-OR list3
    a nomenclatura começa a ficar um pouco inconsistente. Bash chama essas “listas” também; POSIX os chama de "listas", "listas compostas" e (raramente) "termos". Mais uma vez, um indivíduo "AND-OR list", "pipeline" ou até mesmo um "comando simples" individual é considerado uma "lista", mesmo que não contenha & ou ; .
  • Coisas como
    (compound_list)
    e
    { compound_list;}
    e os comandos de controle de fluxo ( for , if - then - else , while , etc.) são chamados de “comandos compostos”.
  • Nos exemplos acima, provavelmente faz mais sentido interpretar A , B e C como pipelines. Lembre-se, um “pipeline” pode ser um “comando simples” individual; não precisa conter um pipe.

        
    por 22.10.2014 / 02:52