web-dev-qa-db-ja.com

2行の長いパイプの推奨構文

長いパイプを書く場合、通常は2行に分ける方が明確です。

この長いコマンドライン:

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

次のように分割できます:

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

または:

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

要するに:

command1 \
    | command2

または:

command1 |
    command2

これはスタイル(意見)の問題である可能性があることは承知していますが、推奨される方法はありますか。

18
Isaac

これで何ができるか自分に尋ねてください。

command1 \ 
   | command2

違いがわかりません。私もできませんが、シェルはできます。よく見て、\の後にスペースがあります。これにより、改行がエスケープされなくなります。

したがって、他の形式を使用するほうが安全です。同じエラー(ここでは|の後のスペース)でここに表示されます。ただし、バグは発生しません。

command1 | 
    command2
40
ctrl-alt-delor

ここではほとんどの人に同意しません。私は常にパイプのような結合演算子beforeをラップすることを好みます:

command1 \
| command 2

(2行目をインデントする必要はありません。パイプ自体が1行目と非常にはっきりとリンクしています。)

これにはいくつかの理由があります。

  • 見やすいジョイナー;ラインの詳細の中で迷子になることはありません。 (これは、ラインが長く、ジョイナーが見えなくなったり、行の折り返しで失われたりする場合に特に重要です。)コードをすばやくスキャンすると、全体が構造化されるため、左側を見下ろします。つまり、インデント、中括弧、または特定の言語が使用するものすべてです。パイプやその他のジョイナーは構造にとって重要であるため、それらも左側に配置する必要があります。

  • It lines up 3行以上にわたる場合。繰り返しになりますが、これにより、パイプラインの構造が一目でわかりやすくなります。

  • 私たちの考え方に近いです。 (これは最も微妙で論争の的となるポイントです...)リストをゆっくりと読んでいて、誰かがそれを書き留めることができる場合、「[アイテム1]…(一時停止)」と言います。 …および[アイテム2]…(一時停止)…および[アイテム3]。”; 「[アイテム1]と…(一時停止)…[アイテム2]と…と言うのは不自然に感じられます(一時停止)…[アイテム3]。」それは、ジョイナーを以前のものよりも次のアイテムにアタッチすると考えているからです。 (算術演算のマイナス記号も同様に考えることができます。これは加算のように機能しますが、次の数値を否定することでより密接に接続します。)コードは、私たちの考えを反映していると従うのが簡単です。

私は何年にもわたって多くの言語で両方の方法を試してきましたが、次の行にジョイナーを置くことはほとんどの場合本当に役立つことがわかりました。

15
gidds

まあ、誰も好まないように見えるのを避けるために:

command1 \
   | command2

私はそうするつもりです。

Ctrl-alt-delorによって引き起こされる後続スペースの問題は問題ではないと思います。編集者はそれについて警告することができます。 gitはそれについて警告します。さらに、シェルは| command2で構文エラーを発生させ、ユーザーにエラーのファイルと行番号を提供し、残りのファイルの解釈を中止します。

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

行継続エスケープの用途が他にもあるという事実もあります。たとえば、多くの引数を持つ単純なコマンドを壊すには:

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

エスケープ後にスペースを入れないと自分自身を信頼できないので、そのような使用法も避けなければなりませんか?

私の好みは、純粋に読みやすさと主観的な問題です。これは私のシェルの歴史からの実際の例です(詳細は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'

と比較:

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'

ここに別のものがあります:

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

と比較:

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

これに対する答えは簡単だと思いましたが、@ JoLと@giddsは私に同意していません。

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.

私のコードを読むと、コメントも問題として表示されます。

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

\または|または||の前に&& +改行を使用すると、パイプラインの途中でどのようにコメントするかはわかりません。それが不可能な場合は、これが最も重要な問題だと思います。コードはコメントなしでは維持できません。コードを変更したときにドキュメントを更新しやすくするために、コメントは通常、できるだけコードに近づけてください。

Emacsは自動的にインデントを行いますので、インデントは余分な負担でさえありません:

# 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