web-dev-qa-db-fra.com

Syntaxe préférée pour une conduite longue de deux lignes

Lors de l'écriture d'un long tuyau, il est généralement plus clair pour la séparer en deux lignes.

Cette longue ligne de commande:

Ruby -run -e httpd -- -p 5000 . 2>&1 | tee >(grep -Fq 'WEBrick::HTTPServer#start' && open localhost:5000) 

Pourrait être divisé comme:

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) 

En bref:

command1 \
    | command2

Ou:

command1 |
    command2

Je me rends compte que cela pourrait être un problème de style (opinion), mais: Y a-t-il une manière préférée, et si oui, pourquoi?

19
Isaac

Demandez-vous à votre auto de quoi cela ferait-il?

command1 \ 
   | command2

Ne peut pas voir la différence. Je ne peux pas non plus, mais la coquille peut. Regardez de près, il y a un espace après le \. Cela empêche la nouvelle ligne d'être échappée.

Par conséquent, utilisez l'autre forme, car il est plus sûr. Montré ici avec la même erreur (un espace après le | dans ce cas). Mais cela ne cause pas de bug.

command1 | 
    command2
40
ctrl-alt-delor

Je vais être en désaccord avec la plupart des gens ici; Je préfère toujours envelopper avant un opérateur de jonction tel qu'un tuyau:

command1 \
| command 2

(Vous n'avez pas besoin d'indenter la deuxième ligne; le tuyau lui-même lie très évidemment à la première.)

Il y a quelques raisons pour cela:

  • Il est plus facile de voir le menuiser; Il ne se perd pas parmi les détails de la ligne. (Ceci est particulièrement important si la ligne est longue et que la menuiser ait peut-être défiler la vue, ou perdue parmi l'enveloppe de ligne.) Lorsque vous numérisez le code rapidement, vous regardez le côté gauche, car c'est là que c'est là que la structure générale est: dans l'indentation, les accolades, ou quelles que soient les utilisations de langues particulières. Les tuyaux et autres menuisiers sont importants pour la structure, de sorte qu'ils devraient aussi être à gauche.

  • il s'inscrit Si vous couvrez 3 lignes ou plus. Encore une fois, cela rend la structure du pipeline facile à prendre en un coup d'œil.

  • Il est plus proche de la façon dont nous pensons. (C'est le point le plus subtil et le plus contentieux ...) Si vous lisez une liste lentement, alors que quelqu'un puisse l'écrire, vous diriez "[article 1] ... (pause) ... et [item 2] ... (pause) ... et [article 3]. "; Il se sentirait unin naturel de dire "[article 1] et ... (pause) ... [Item 2] et ... (Pause) ... [article 3]. " C'est parce que nous pensons que le menuiser est en train de joindre à l'élément suivant plus que le précédent. (Vous pouvez penser au signe moins en arithmétique dans des termes similaires; cela fonctionne comme une addition, mais se connecte plus près au numéro suivant en négociant.) Le code est plus facile à suivre quand il reflète notre pensée.

J'ai essayé à la fois de nombreuses langues au fil des ans et j'ai constaté que la mise en place des menuisiers sur la ligne suivante contribue vraiment dans la plupart des cas.

15
gidds

Eh bien, juste pour éviter de ressembler à personne préférerait:

command1 \
   | command2

Je vais dire que je fais.

Je vois le problème d'espace suivi soulevé par Ctrl-Alt-Delor en tant que non-problème. Les éditeurs peuvent avertir à ce sujet; Git avertit de ça. Pour terminer le top, la coque augmenterait une erreur de syntaxe sur | command2, fournissant à l'utilisateur le fichier et le numéro de ligne de l'erreur et cessez d'interpréter le reste du fichier:

$ 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'

Il y a aussi le fait qu'il y ait plus d'utilisations pour les évasions de continuation de la ligne. Par exemple, pour casser des commandes simples qui ont de nombreux arguments:

ffmpeg \
  -f x11grab \
  -video_size "$size" \
  -framerate "${framerate:-10}" \
  -i "${DISPLAY}${offset}" \
  -c:v ffvhuff \
  -f matroska \
  -

Devrions-nous éviter une telle utilisation parce que nous ne pouvons pas nous faire confiance à ne pas mettre de l'espace après l'évasion?

Ma préférence est purement une question de lisibilité et assez subjective. Voici un exemple de vie réelle de mon historique de shell (avec des détails substitués par 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'

Comparer aux:

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'

Voici un autre:

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

Comparer aux:

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
9
JoL

Je pensais que la réponse à cela était facile, mais je peux voir @jol et @gidds en désaccord avec moi.

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.

Lecture de mon code, je vois aussi des commentaires comme un problème:

foo ... ... ... ... ... ... ... ... |
    # Now this does bar
    bar ... ... ... ... ... ... ... ... ||
    # And if that fails: fubar
    fubar

Je ne sais pas comment vous feriez du tout commenter au milieu d'un pipeline si vous utilisez \ + nouvelle ligne avant | ou || ou &&. Si cela n'est pas possible, je pense que c'est le problème le plus important. Le code n'est pas maintenu sans commentaires et les commentaires doivent normalement être aussi proches du code que possible pour encourager la mise à jour de la documentation lorsque vous modifiez le code.

Emacs fait l'indentation pour moi automatiquement, de sorte que l'indentation n'est même pas un fardeau supplémentaire:

# 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
7
Ole Tange