web-dev-qa-db-ja.com

ワンライナーvsスクリプト

私は、ワンライナーの代わりにスクリプトを書くことに対する軽蔑(そして時には恐れさえする)を表す多くの質問と回答、コメントに気づきました。だから、私は知りたい:

  • 「ワンライナー」ではなくスタンドアロンのスクリプトを作成する必要があるのはいつですか。なぜですか。またはその逆?

  • 両方のユースケースと長所と短所は何ですか?

  • 一部の言語(例:awkまたはPerl)は、他の言語(例:python)よりもワンライナーに適していますか?もしそうなら、なぜですか?

  • それは単に個人的な好みの問題ですか、それとも特定の状況でどちらか一方を書くのに十分な(つまり客観的な)理由がありますか?それらの理由は何ですか?

定義

  • one-liner:入力または貼り付けられたコマンドのシーケンスシェルコマンドラインに直接。多くの場合、パイプラインやsedawkPerlなどの言語、およびgrepcutなどのツールの使用が含まれます。またはsort

    定義の特徴であるのは、コマンドラインでの直接の実行です。長さとフォーマットは関係ありません。 「ワンライナー」はすべて1行にある場合もあれば、複数の行がある場合もあります(たとえば、sh forループ、または埋め込みawkまたはsedコード、読みやすさを向上させるための改行およびインデント付き)。

  • script:解釈された言語のコマンドシーケンスファイルに保存であり、実行されます。スクリプトは、完全に1つの言語で記述される場合と、他の言語を使用する複数の「ワンライナー」を囲むシェルスクリプトラッパーである場合があります。


私自身の回答があります(これについては後で投稿します)が、これは私の個人的な意見だけでなく、この件に関する標準的なQ&Aになりたいです。

25
cas

実務経験に基づく別の対応。

プロンプトで直接書き込める「捨てる」コードであれば、ワンライナーを使用します。たとえば、私はこれを使うかもしれません:

for h in Host1 Host2 Host3; do printf "%s\t%s\n" "$h" "$(ssh "$h" uptime)"; done

コードを保存する価値があると判断した場合は、スクリプトを使用します。この時点で、ファイルの先頭に説明を追加し、おそらくいくつかのエラーチェックを追加し、バージョン管理のためにコードリポジトリにチェックインすることもできます。たとえば、一連のサーバーの稼働時間をチェックすることが繰り返し使用できる便利な機能であると判断した場合、上記の1行は次のように拡張できます。

#!/bin/bash
# Check the uptime for each of the known set of hosts
########################################################################
#
hosts=(Host1 Host2 Host3)

for h in "${hosts[@]}"
do
    printf "%s\t" "$h"
    uptime=$(ssh -o ConnectTimeout=5 -n "$h" uptime 2>/dev/null)
    printf "%s\n" "${uptime:-(unreachable)}"
done

一般化すると、

  • 一発ギャグ

    • 特定の1回限りの目的のために記述された単純なコード(つまり、「いくつかの」ステートメントのみ)
    • 必要なときにいつでも簡単に記述できるコード
    • 使い捨てコード
  • 脚本

    • (おそらく)2回以上使用されるコード
    • 「少数」以上のステートメントを必要とする複雑なコード
    • 他の人が保守する必要があるコード
    • 他の人が理解できるコード
    • 無人で実行するコード(たとえば、cronから)

nix.SE でかなりの数の質問が表示されます。特定のタスクを実行するためにワンライナーを要求します。上記の例を使用すると、2番目の方法は最初の方法よりもはるかに理解しやすいと思います。したがって、読者はそれからより多くを学ぶことができます。 1つのソリューションは他のソリューションから簡単に導き出せるため、読みやすさの観点から(将来の読者のために)最も簡単なソリューション以外には、1行に詰め込まれたコードを提供しないようにする必要があります。

33
roaima

scriptの場合:

  • より多くのコードが必要です
  • 読みやすさを重視
  • コードが何をするかを示すために、コメントを追加することが必要/有用です
  • パラメータを渡す必要があります
  • スクリプトを独自の環境(変数など)で実行したい
  • おそらくより複雑な目的のためにコードを再利用/適応するでしょう

one-linerの場合:

  • ほんの少しのコードが必要です
  • 現在のシェルで定義されている変数にアクセスしたい
  • あなたは迅速で汚い解決策を必要としています
10
dr_

必要な一連のコマンドがかなり短い場合、および/またはより大きなパイプラインまたはコマンドエイリアスの一部として使用できる結果が生成される場合は、適切なワンライナーである可能性があります。

基本的に、ワンライナーは通常、問題と使用されるコマンドの両方に精通した経験豊富なシステム管理者が、あまり考えずにその場で書くことができるものだと思います。

ワンライナーが過度に長くなる場合や、非常に単純な条件やループ以上のものが含まれる場合は、読みやすくするために、通常は複数行のスクリプトまたはシェル関数として記述する方が適切です。また、それが何度も使用されるように書くもの、または他の人が使用する(そしておそらくトラブルシューティングする)ものである場合は、解決策をクリアに書いて時間を費やすことをいとわないはずです、とコメントしました、スクリプトフォーム。

Pythonでは、インデントは構文の一部であるため、ワンライナーを記述する場合、文字通り言語の機能を最大限に使用することはできません。

Perlとawkのワンライナーは、多くの場合、正規表現の生の力を利用しようとしています。しかし、完全な理由がないわけではなく、正規表現を書き込み専用言語と呼ぶ人もいます。複数行のスクリプトを書くと、特定の正規表現が何をすることになっているかを説明するコメントを書くことができます。これは、6か月間他のことを行った後で、スクリプトをもう一度見るときに非常に役立ちます。

これは本質的に非常に意見に基づく質問です。これは、許容できる複雑さの量と、読みやすさとコンパクトさの間のトレードオフを測定する必要があるためです。これらはすべて個人的な判断の問題です。言語の選択でさえ個人的な事柄に依存する可能性があります。特定の言語が理論的に特定の問題に最適であるが、それに慣れておらず、他の言語で問題を解決する方法をすでに知っている場合は、解決策は技術的にいくらか非効率的かもしれませんが、仕事を迅速かつ最小限の労力で完了するための使い慣れた言語。

最高はしばしば十分良いの敵であり、これはここで非常に当てはまります。

また、Perlに精通している場合は、TMTOWTDIについて聞いたことがあるかもしれません。それを行う方法は1つではありません。

9
telcoM

これは個人的な意見であることに注意してください。一粒の塩と一緒に服用してください。

  1. コマンドが80文字以内に収まる場合は、ワンライナーを使用します。長いコマンドラインは扱いにくいです。再発の問題もあります。#2を参照してください

  2. コマンドを複数回実行する必要がある場合は、スクリプトを使用します。それ以外の場合は、条件#1が満たされていれば、ワンライナーを使用します。

  3. これはvery主観的ですが、そうです、私はシェル、Perl、またはawkをワンライナーの頼りになるツールであると考えています。
  4. #1、#2、#3を参照してください。
7
schaiba

私は、ワンライナーを一時的な開発ツールとして表示して使用し、必要なことを実行するまで、またはサブコマンドの微妙な機能がどのように機能するかを理解するまで繰り返し編集します。

次に、調査中の件名のテキストファイルに注記(および注釈)が付けられるか、スクリプトにクリーンアップされて、個人用ビンのPATHに入れられ、場合によっては、さらに詳細化、パラメーター化などが行われます。通常、他の変更が行われなかったり、スクリプトを再度使用したりしなくても、1行は読みやすくなるように分割されます。

シェルの履歴を5000行以上に設定し、端末ごと、およびリモートでのログインごとなどに個別の履歴を設定しました。数週間前に作成した1行のコマンドをこれらの履歴で見つけることができず、再び必要になるとは思っていなかったので、私の戦略です。

場合によっては、コマンドのグループ全体で、ハードウェアの構成など、何かを行う必要があります。最後に、それらをすべて履歴からコピーし、最小限にクリーンアップして、シェルスクリプトに追加しますRUNMEは、私がやったことのメモとしてだけでなく、ほぼ再び使用できるようになります。他の誰かによって。 (これが、GUIを提供するだけでツールを見つけるような苦痛を感じる理由です。)これは非常に効率がよくなると感じています。 。

7
meuh

私は、質問の最初の部分の含意に少し恐怖を感じていると言わざるを得ません。 Unixスクリプト言語は本格的なプログラミング言語であり、プログラミング言語はlanguagesです。つまり、人間の言語と同じくらい無限に柔軟で柔軟性があります。そして、「無限の柔軟性と柔軟性」の特徴の1つは、何かを表現する「正しい方法」がほとんどないことです。さまざまな方法があり、これは良いことです。ですから、はい、もちろんこれは個人的な好みの問題であり、何の問題もありません。何かをする方法は1つしかないと言っている人は誰でも、何らかの方法で何かをしている(またはしていない)ことについて軽蔑を表明した人は、おそらくペダントまたは規範主義者です。

むかしむかし、自分の~/binだったfull私が書いた「便利な」小さなスクリプトの数。しかし、私はそれらのほとんどが私がそれらを書いた日に使用され、二度と二度と使用されないことに気付きました。したがって、時間が経過するにつれて、私のbinディレクトリは小さくなります。

スクリプトを書くとき、何かあるとは思いませんwrong。あなたや他の誰かが再びそれを使用する可能性があると想像する場合は、必ず、スクリプトを記述してください。そのためにサポート可能なスクリプトを「適切に設計」したい場合は、必ずそうしてください。 (誰もそれを使用したことがなくても、それを書くことは良い習慣です。)

私がこれ以上スクリプトを書かない理由(そして私は、おそらく「ワンライナー」を支持します):

  • binディレクトリの整理にはコストがかかります。彼らが本当にそこに属さない限り、私はそれ以上そこに物を置かない。
  • 私が使用するスクリプト言語は、私が使用する言語ですse;私は今、彼らと本当に仲良くしています。必要なときにワンライナーを再入力するのは、仕事のようには感じられません。 (再)タイピングの負担を軽減するためだけにスクリプトを保存して保存し、使用する義務を感じていません。 (とりわけ、ある時点で、再入力の負担は、スクリプトが何であるかを覚えているメモリの負担より少なくなります。)
  • 再入力が負担にならないもう1つの理由は、コマンド履歴です。毎日使用しているにもかかわらず、スクリプトとして安置していない1行がたくさんありますが、再入力する必要はありません。私はそれらを歴史から思い出すだけです。そのように、それらは一種の貧乏人のスクリプトまたはエイリアスです。
5
Steve Summit

私はこれについて少数派の見解を持っているようです。

「スクリプト」という用語は意図的に紛らわしいので、取り除いてください。 これはソフトウェアですbashawkだけを使用している場合でも、そこに書いています。

チーム内では、ツール(github/gitlab/gerrit)によってコードレビュープロセスが実行されるソフトウェアを作成することを好みます。これは、ボーナスとしてバージョン管理を提供します。複数のシステムがある場合は、継続的な展開ツールを追加します。ターゲットシステムが重要な場合は、いくつかのテストスイート。私はこれらについては信心深くありませんが、利益とコストを比較検討しています。

管理者のチームがある場合、最も簡単なvim /root/bin/x.shは、変更関連の通信、コードの読みやすさ、およびシステム間の分散という点で、ほとんどが災害です。多くの場合、1つの深刻な機能不全は、「重い」と思われるプロセスよりも多くの時間/お金がかかります。

私は1行を推奨実際には、その「重い」プロセスに値しないすべてのものに使用します。シェルの履歴を効果的に使用する方法を知っている場合は、キーを数回押すだけですばやく再利用できます。関連のないシステム(異なる顧客など)間で簡単に貼り付けられます。

(未レビュー!)ワンライナーとレビュー済みソフトウェア(「スクリプト」)の重大な違い:ワンライナーを実行するときの責任は完全にあなたにあります。 「このワンライナーをどこかで見つけたので、理解せずに実行しました。その後は何も私のせいではありません」-まだレビューされていない、テストされていないソフトウェアを実行していることがわかったので、isあなたの責任です。結果が予測できる程度に小さいことを確認してください。そうでない場合は、のろわれてしまいます。

この単純化したアプローチが必要になる場合があり、バーをテキストの約1行に設定すると、実際にはうまく機能します(つまり、レビュー済みコードと未レビューコードの境界)。一部のワンライナーは恐ろしく長く見えますが、私にとっては効果的です。私がそれらを手に取って、それをもっと若い同僚に押し付けない限り、それはすべて大丈夫です。それらを共有する必要がある瞬間-私は標準的なソフトウェア開発プロセスを経ます。

5
kubanczyk

私のチームのメンバーは、複数回実行する必要がある操作(つまり、「ワークフロー」または「パイプライン」)や、文書化する必要のある1回限りのタスク(通常、私たちの場合、「誤って提供されたデータを修正するために、データセットの特定のものを変更する」のようなもの)。それとは別に、「ワンライナー」またはスクリプトはあまり重要ではありません。

ワークフローを(スクリプトまたは同等のものとして)適切に文書化しないと、プロジェクトに新しいスタッフを紹介することが難しくなり、プロジェクトから人を移行することが難しくなります。さらに、あらゆる種類の監査が困難になり、バグの追跡が不可能になる場合があります。

これは、プログラミングにどの言語が使用されているかに関係なくです。

他の職場では、同様の/異なる習慣や期待があり、場合によっては書き留められることもあります。

家では、好きなことを何でもします。

たとえば、U&Lの質問への回答を送信する前や、コマンドやセットの個々のコンポーネントをテストする必要があるときなど、シェルで何か重要なを実行するとすぐにスクリプトを記述します「実際に」実行する前のコマンドの数。

また、次のような単純なものでも、毎回同じようにしたい繰り返しタスクのスクリプトも作成します。

  • openBSDシステムとすべてのインストール済みパッケージを更新する(これは、3つの短いコマンドと、ハウスキーピング用の他の少数のコマンドになり、短いスクリプトで収集されます)、または
  • 私のシステムをオフサイトのストレージにバックアップします(基本的にはsingleコマンドですが、これもかなりのハウスキーピングとスクリプトを使用して、スナップショット間の差分を作成できるようにします。システムによって微妙に異なり、cronジョブから実行した場合)、または
  • メールのフェッチ(ここでも、基本的に単一のコマンドですが、cronジョブとして呼び出されたときとコマンドラインから使用したときの動作が異なり、状況によってはメールのフェッチを試みるべきではありません。ファイルへの短いログメッセージ)。

私はconvenienceにシェル関数(エイリアスはほとんどありません)をインタラクティブなシェルで使用しています。デフォルトで特定のコマンドにオプションを追加するには(-F for ls)またはいくつかのコマンドの特殊なバリエーションを作成します(たとえば、pmanはPOSIXマニュアルのみを参照するmanコマンドです)。

5
Kusalananda

ほとんどの場合、「ワンライナー」の要求は、実際には「サウンドバイト」の要求であると考えています。つまり、

ジャーナリズムの文脈では、音のかみ傷は、話し手が言っていることの本質をとらえた短いフレーズまたは文によって特徴付けられ、情報を要約するために使用されます...

人々は、尋ねられた質問に対する解決策を示す最短のコードを望み、要求します。

時々、スピーチを「サウンドバイト」に削減する方法がない場合や、スクリプトを短い「ワンライナー」に削減できない場合があります。そのような場合、唯一の可能な答えはスクリプトです。

そして、一般的に、「音のかみ傷」は、スピーチ全体の良い代用にはなりません。したがって、「ワンライナー」は一般に、アイデアを伝えるか、そのアイデアの実用的な例を示すためだけに適しています。次に、アイデアが理解されたら、スクリプトで展開(適用)する必要があります。

したがって、アイデアやコンセプトを伝える「ワンライナー」を作成してください。

一般的なコードは、ワンライナーではなく完全なスクリプトとして記述します。

4
Isaac

「スクリプトに対する恐れと軽蔑」について尋ねます。これはQ + Aの状況によるもので、よく答えはこうです:このステップとこれが必要ですが、1行に入れることもできます(コピーして貼り付けて、長くてシンプルなコマンドとして使用してください)

場合によっては、Qが迅速でダーティーなコピーペーストソリューションによってより適切に提供されるか、または「ナイス」スクリプトがQが理解する必要があるものであるかを推測できるだけです。

ここで多くの長所と短所は真実ですが、それでも彼らはポイントを逃しています。 Qの定義は役に立たないとも言えます。

シェルhistoryファイルは「ワンライナー」ですが、それでも保存されます。 bash関数operate-and-get-next (C-o)では、それらを半自動的に繰り返すこともできます。

functionという言葉はほとんど見かけません。これが「スクリプト」と「ワンライナー」の両方を保存する方法です。また、いくつかのキーストロークで、両方の形式を切り替えることができます。 複合コマンドは多くの場合、両方に適合します。

_history -r file_は、デフォルトの履歴ファイルだけでなく、任意のファイルから1つまたは複数のコマンド行(およびコメント)を読み取る方法です。最小限の組織化が必要です。コマンドラインの(一部の)バージョンを取得するために、大きな履歴ファイルサイズと履歴検索に依存すべきではありません。

関数も同様に定義する必要があります。まず、ホームディレクトリの「functions」ファイルにthisfunc() {...}を置き、ソースを取得します。はい、これはある程度のオーバーヘッドですが、これは一般的な解決策です。

すべてのコマンドラインとすべてのスクリプトのバリエーションを個別のファイルに保存すると、ファイルシステムブロックの無駄(理論的だが客観的)になります。

ワンライナーは、それだけでは速くて汚いものはありません。それは、コピーと貼り付けの部分であり、少し不満を感じています。また、コマンド履歴を使用して保存する方法に依存しています。


@sitaram:あなたのワンライナーは本当にun-onelinerish機能を持っています:シバン行、改行、4つのユーティリティ呼び出し-それらの2つは「プログラム」をsedしました。元のPerlスクリプトは見た目がよく、実行速度も速く、60行に分散することでバイトを浪費しなかったと思います。また、Perlを使用すると、かなりの範囲を絞ることもできます。

私にとって、それはまさに避けるべき一種のライナーです。コマンドラインにそれを貼り付けたいですか?いいえ、とにかくそれをファイルに保存すると(スクリプトや関数に関係なく)、見栄えを良くするために2行または3行の改行バイトを投資することになるでしょう---いいですね。


10分。後で:「2つのsedプログラム」と言えるのか、それとも「2つのsed置換/呼び出し」なのかを確認したかっただけです。しかし、シタラムの答えはなくなった。私の返事は今でも理にかなっています。

1
rastafile