
Ao escrever um tubo longo, geralmente é mais claro separá-lo em duas linhas.
Esta longa linha de comando:
ruby -run -e httpd -- -p 5000 . 2>&1 | tee >(grep -Fq 'WEBrick::HTTPServer#start' && open localhost:5000)
Poderia ser dividido como:
ruby -run -e httpd -- -p 5000 . 2>&1 \
| tee >(grep -Fq 'WEBrick::HTTPServer#start' && open localhost:5000)
Ou:
ruby -run -e httpd -- -p 5000 . 2>&1 |
tee >(grep -Fq 'WEBrick::HTTPServer#start' && open localhost:5000)
Resumidamente:
command1 \
| command2
Ou:
command1 |
command2
Sei que esta pode ser uma questão de estilo (opinião), mas: existe uma forma preferida e, em caso afirmativo, por quê?
Responder1
Pergunte a si mesmo o que isso faria?
command1 \
| command2
Não consigo ver a diferença. Nem eu posso, mas a casca pode. Olhe atentamente, há um espaço após o \
. Isso impede que a nova linha seja escapada.
Portanto use a outra forma, pois é mais segura. Mostrado aqui com o mesmo erro (um espaço após |
neste caso). Mas isso não causa um bug.
command1 |
command2
Responder2
Vou discordar da maioria das pessoas aqui; Eu sempre prefiro embrulharantesum operador de união, como um tubo:
command1 \
| command 2
(Você não precisa recuar a segunda linha; o próprio tubo a vincula obviamente à primeira.)
Existem algumas razões para isso:
É mais fácil vero marceneiro; não se perde entre os detalhes da linha. (Isso é especialmente importante se a linha for longa e o marceneiro puder ter sido rolado para fora da vista ou perdido na quebra de linha.) Ao digitalizar o código rapidamente, você olha para o lado esquerdo, porque é onde está a estrutura geral. é: no recuo, nas chaves ou no que quer que um idioma específico use. Tubos e outras juntas são importantes para a estrutura, por isso também devem ficar à esquerda.
Ele se alinhase você estiver abrangendo 3 ou mais linhas. Novamente, isso torna a estrutura do pipeline fácil de entender rapidamente.
Está mais próximo da maneira como pensamos. (Este é o ponto mais sutil e controverso…) Se você estiver lendo uma lista lentamente, para que alguém possa anotá-la, você diria “[Item 1]…(pausa)… e [Item 2]…(pausa)… e [Item 3].”; não seria natural dizer “[Item 1] e…(pausa)… [Item 2] e…(pausa)… [Item 3].” Isso porque pensamos que o marceneiro está apegado ao item seguinte mais do que ao anterior. (Você pode pensar no sinal de menos na aritmética em termos semelhantes; ele funciona como uma adição, mas se conecta mais estreitamente ao número seguinte, negando-o.) O código é mais fácil de seguir quando reflete nosso pensamento.
Eu tentei as duas maneiras em vários idiomas ao longo dos anos e descobri que colocar joiners na linha a seguir realmente ajuda na maioria dos casos.
Responder3
Bem, só para evitar que pareça que ninguém preferiria:
command1 \
| command2
Eu vou dizer que sim.
Vejo o problema de espaço à direita levantado por ctrl-alt-delor como um problema. Os editores podem alertar sobre isso; git avisa sobre isso. Para completar, o shell geraria um erro de sintaxe on | command2
, fornecendo ao usuário o arquivo e o número da linha do erro e pararia de interpretar o restante do arquivo:
$ cat f.sh
#!/bin/bash
echo foo \
| command2
echo bar
$ ./f.sh
foo
./f.sh: line 4: syntax error near unexpected token `|'
./f.sh: line 4: `| command2'
Há também o fato de que há mais usos para escapes de continuação de linha. Por exemplo, para quebrar comandos simples que possuem muitos argumentos:
ffmpeg \
-f x11grab \
-video_size "$size" \
-framerate "${framerate:-10}" \
-i "${DISPLAY}${offset}" \
-c:v ffvhuff \
-f matroska \
-
Deveríamos evitar esse uso também porque não podemos confiar em nós mesmos para não colocarmos um espaço após a fuga?
Minha preferência é puramente uma questão de legibilidade e bastante subjetiva. Aqui está um exemplo real do meu histórico de shell (com detalhes substituídos por foobar):
org-table-to-csv foobar.org \
| cq +H -q "
select foo
from t
where bar = 'baz'
and foo != ''" \
| sed -r 's/^|$/'\''/g' \
| sed -r ':b;$!{N;bb};s/\n/, /g'
Comparado a:
org-table-to-csv foobar.org |
cq +H -q "
select foo
from t
where bar = 'baz'
and foo != ''" |
sed -r 's/^|$/'\''/g' |
sed -r ':b;$!{N;bb};s/\n/, /g'
Aqui está outro:
sed 's/ .*//' <<< "$blame_out"
| sort \
| uniq \
| tee >(sed "s/^/from pipe before grep filtering: /" > /dev/tty) \
| grep -vF "$(git show -s --format=%h "$from_commit")" \
| tee >(sed "s/^/from pipe before git show: /" > /dev/tty) \
| xargs git show -s --format='%cI %h' \
| tee >(sed "s/^/from pipe after git show: /" > /dev/tty) \
| sort -k1 \
| tail -1 \
| cut -d' ' -f2
Comparado a:
sed 's/ .*//' <<< "$blame_out"
sort |
uniq |
tee >(sed "s/^/from pipe before grep filtering: /" > /dev/tty) |
grep -vF "$(git show -s --format=%h "$from_commit")" |
tee >(sed "s/^/from pipe before git show: /" > /dev/tty) |
xargs git show -s --format='%cI %h' |
tee >(sed "s/^/from pipe after git show: /" > /dev/tty) |
sort -k1 |
tail -1 |
cut -d' ' -f2
Responder4
Achei que a resposta era fácil, mas vejo que @JoL e @gidds discordam de mim.
My brain prefers reading a line and not having to scan the next line \
:
foo bar baz ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... \
In the above I will have to see \
, what is on line 2 \
, before I can tell \
, what the command does \
. Maybe the command is complete \
? Or maybe the command continues \
on the next line \
?
To me it is much easier to read,
if \ is only used,
when a command cannot fit on a line.
Lendo meu código, também vejo os comentários como um problema:
foo ... ... ... ... ... ... ... ... |
# Now this does bar
bar ... ... ... ... ... ... ... ... ||
# And if that fails: fubar
fubar
Não tenho certeza de como você faria comentários no meio de um pipeline se usasse \
+ nova linha antes de |
or ||
or &&
. Se isso não for possível, penso que este é o problema mais importante. O código não pode ser mantido sem comentários, e os comentários normalmente devem estar o mais próximo possível do código para incentivar a atualização da documentação quando você altera o código.
O Emacs faz o recuo automaticamente para mim, então o recuo não é nem um fardo extra:
# This is indented automatically in emacs
ruby -run -e httpd -- -p 5000 . 2>&1 |
# Send the output to the screen and to grep
tee >(grep -Fq 'WEBrick::HTTPServer#start' &&
# If grep matches, open localhost:5000
open localhost:5000)
# Here is where emacs indents the next command to