Sintaxis preferida para tuberías largas de dos líneas

Sintaxis preferida para tuberías largas de dos líneas

Al escribir una pipa larga suele ser más claro separarla en dos líneas.

Esta larga línea de comando:

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

Podría dividirse como:

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

O:

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

En breve:

command1 \
    | command2

O:

command1 |
    command2

Me doy cuenta de que esto podría ser una cuestión de estilo (opinión), pero: ¿existe una forma preferida y, de ser así, por qué?

Respuesta1

Pregúntate ¿qué haría esto?

command1 \ 
   | command2

No puedo ver la diferencia. Yo tampoco, pero el caparazón sí. Fíjate bien, hay un espacio después del \. Esto evita que se escape la nueva línea.

Por tanto, utilice la otra forma, ya que es más segura. Se muestra aquí con el mismo error (un espacio después de |en este caso). Pero no causa ningún error.

command1 | 
    command2

Respuesta2

No estaré de acuerdo con la mayoría de la gente aquí; Siempre prefiero envolverantesun operador de unión como una tubería:

command1 \
| command 2

(No es necesario sangrar la segunda línea; la tubería en sí la vincula de manera muy obvia con la primera).

Hay algunas razones para esto:

  • es más fácil de verel carpintero; no se pierde entre los detalles de la línea. (Esto es especialmente importante si la línea es larga y es posible que el carpintero se haya desplazado fuera de la vista o se haya perdido entre el ajuste de línea). Cuando escanea el código rápidamente, mira hacia abajo en el lado izquierdo, porque ahí es donde se encuentra la estructura general. es: en la sangría, las llaves o lo que sea que use un idioma en particular. Las tuberías y otros elementos de unión son importantes para la estructura, por lo que también deben estar a la izquierda.

  • se alineasi abarca 3 o más líneas. Nuevamente, esto hace que la estructura de la tubería sea fácil de ver de un vistazo.

  • Está más cerca de la forma en que pensamos.. (Este es el punto más sutil y polémico…) Si estás leyendo una lista lentamente, para que alguien pueda escribirla, dirías “[Elemento 1]…(pausa)… y [Ítem 2]…(pausa)… y [Punto 3].”; Sería antinatural decir “[Ítem 1] y…(pausa)… [Ítem 2] y…(pausa)… [Ítem 3].” Esto se debe a que pensamos que el elemento de unión se adjunta al siguiente elemento más que al anterior. (Puedes pensar en el signo menos en aritmética en términos similares; funciona como la suma, pero se conecta más estrechamente con el siguiente número al negarlo). El código es más fácil de seguir cuando refleja nuestro pensamiento.

He probado ambas formas en muchos idiomas a lo largo de los años y descubrí que poner elementos de unión en la siguiente línea realmente ayuda en la mayoría de los casos.

Respuesta3

Bueno, sólo para evitar que parezca que nadie lo preferiría:

command1 \
   | command2

Voy a decir que sí.

Considero que el problema del espacio final planteado por ctrl-alt-delor no es un problema. Los editores pueden advertir al respecto; git advierte al respecto. Para colmo, el shell generaría un error de sintaxis en | command2, proporcionando al usuario el archivo y el número de línea del error y dejaría de interpretar el resto del archivo:

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

También está el hecho de que existen más usos para los escapes de continuación de línea. Por ejemplo, para descifrar comandos simples que tienen muchos argumentos:

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

¿Deberíamos evitar ese uso también porque no podemos confiar en nosotros mismos para no poner un espacio después del escape?

Mi preferencia es puramente una cuestión de legibilidad y bastante subjetiva. Aquí hay un ejemplo de la vida real de mi historial de shell (con detalles sustituidos 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'

Comparar con:

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'

Aquí está otro:

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

Comparar con:

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

Respuesta4

Pensé que la respuesta a esto era fácil, pero veo que @JoL y @gidds no están de acuerdo conmigo.

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.

Al leer mi código, también veo los comentarios como un problema:

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

No estoy seguro de cómo harías comentarios en medio de una canalización si usas \+ nueva línea antes de |o ||o &&. Si eso no es posible, creo que éste es el problema más importante. El código no se puede mantener sin comentarios, y los comentarios normalmente deben estar lo más cerca posible del código para fomentar la actualización de la documentación cuando se cambia el código.

Emacs hace la sangría automáticamente, por lo que la sangría ni siquiera es una carga adicional:

# 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

información relacionada