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


25

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

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

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

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

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

定義

  • one-linerシェルコマンドラインに直接入力または貼り付けられた一連のコマンド。多くの場合、関係するパイプラインおよび/またはなどの言語の使用sedawkperl、および/またはツールのようなgrepまたはcutまたはsort

    定義する特性であるのは、コマンドラインでの直接実行です-長さとフォーマットは無関係です。「ワンライナー」は、すべて1行にすることも、複数行にすることもできます(たとえば、sh for loop、埋め込みawkまたはsedコード、改行とインデントを使用して読みやすくします)。

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


私は自分の答えを持っています(後で投稿します)が、これは私の個人的な意見だけでなく、主題に関する標準的なQ&Aになりたいです。



4
Pythonについては、空白はインデントや改行を含む構文の一部であるため、一般にワンライナーには適していません。同様に、他のほとんどの一般的な言語よりも冗長で明示的です。
wjandrea

2
私がグーグルに持っていたもの(通常は正規表現)と何らかの形やバリアントで再利用する可能性のあるものはすべて、クラウド(Dropbox、グーグルクラウドなど)のスクリプトファイルに保存します。解説には、今後必要になるときに使用することがわかっているキーワードが含まれています。5分以上の時間を節約して、同様のさまざまな回答の選択肢を再検討し、落とし穴を回避したり、必要な正確に記述されたバリアントが見つからなかったために必要なバリアントを構築したりします。
user3445853

3
@wjandrea追加するには:正規表現。Perlには、実行する操作などを含む特定の構文があります。Pythonでは、文字列リテラルを引数として使用して、より多くの文字を受け取る関数呼び出しをインポートおよび記述する必要があります。ほとんどのワンライナーは多くの正規表現を使用してテキストを操作するため、これは「大きな問題」です。
ジャコモアルゼッタ

1
@wjandrea Pythonはワンライナーにとって悪いことではありません。1つ書くことができないという意味ではありません。平均して、4〜5行のスクリプトを1行に変換できました。しかし、あなたが述べたように、それは他の言語(Pythonの利点の1つです)よりも明確です。そのため、Perlやawk(Pythonとは異なりいくつかのライブラリをインポートする必要もありません)と言うよりも、2文字または3文字のカウントになります。しかし、再び、私見では、文字数について議論するのはささいなことです。何かが機能する場合-動作する
セルギー・コロディアズニー

回答:


33

実際の経験に基づく別の応答。

プロンプトで直接記述できる「スローアウェイ」コードである場合は、ワンライナーを使用します。たとえば、私はこれを使用するかもしれません:

for h in host1 host2 host3; do printf "%s\t%s\n" "$h" "$(ssh "$h" uptime)"; done

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

#!/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回限りの目的のために記述された単純なコード(つまり、「少数の」ステートメント)
    • 必要なときにいつでもすばやく簡単に記述できるコード
    • 使い捨てコード
  • スクリプト

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

unix.SEには、特定のタスクを実行するためのワンライナーを求めるかなりの数の質問があります。上記の例を使用すると、2番目の方法は1番目の方法よりもはるかに理解しやすいため、読者はそれからより多くを学ぶことができます。1つのソリューションは他のソリューションから簡単に派生できるため、読みやすさ(将来の読者向け)のために、おそらく最も単純なソリューション以外のコードを1行に詰め込んで提供することは避けてください。


これは、迅速で汚いワンライナーがより堅牢なスクリプトに進化する方法の良い実用的な例です。
アンソニーG-モニカの正義

これは良いスタートですが、もう1つの可能性があります。同じマシン上ではないかもしれませんが、複数回使用するのに便利なものがいくつかあります。作業用コンピューターで常に開いたままにしておくテキストファイルに保存します。これにより、それらをすばやくコピーして、SSHクライアント(またはWindowsサーバーのコマンドプロンプト)に貼り付けることができます。これらは必ずしも「1つのライナー」ではなく、「スクリプト」としてファイルに保存する努力もしません。私はそれらを「レシピ」と呼びます。
モンティハーダー

@MontyHarderこのような場合、私はそれらをスクリプトとして保存し、gitリポジトリに保存する傾向があります。その後、単純なgitクローンを介して、必要なマシンに簡単にインストールできます。それは仕事のためです。個人的な使用のために、「レシピ」ファイルにコードを書くことはありません(たとえば、githubスニペットを使用しません)。すべてのスクリプトは、1997年の大学時代(大学SunOS上)から保持していた$ HOME / binディレクトリに保存します。私は主人公とアンタゴニストの両方を武器として使用するために個人的なスクリプト/プログラムを保持小説ニューロマンサーからアイデアを得た
slebetman

1
確かに実際の議論とは正反対ですが、サンプルスクリプトではset -- host1 host2 host3then for h in "$@"(または単にfor h)を使用できます。これにより、スクリプトがPOSIX移植可能になります。:-)
wchargin

2
OPと視聴者がコードをより読みやすくする点が気に入っています。おそらく答えの両方を行うのが最善ですが、スクリプトを連結する方が、ライナーを個人的に分解するよりも簡単です。
FreeSoftwareServers

10

次の場合にスクリプトを作成します

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

次の場合にワンライナーを作成します。

  • 必要なコードはわずかです
  • 現在のシェルで定義された変数にアクセスしたい
  • 迅速で汚れたソリューションが必要です

通常、ワンライナーの操作対象を変更するのは簡単です。スクリプトの「パラメータを渡す」ポイントは、「後で簡単に使用できるようにパッケージ化したい」ということでしょう。シェル関数の定義と呼び出しを含む「ワンライナー」を作成しました。今考えてみましたが、何回か繰り返して落ち着いたので、スクリプトに入れる必要があります。
ピーターコーデス

9

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

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

ワンライナーが過度に長くなるか、非常に単純な条件またはループ以上のものを含む場合、通常、読みやすくするために、それらを複数行のスクリプトまたはシェル関数として記述することをお勧めします。また、繰り返し使用するために書いたもの、または他の人が使用する(そしておそらくトラブルシューティングする)ものであれば、あなたは解決策を明確な(er)に書き、コメントし、スクリプト形式。

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

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

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

多くの場合、最高の敵は十分な敵であり、これはここで非常に当てはまります。

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


「またはシェル関数」に言及するための1つ
グレンジャックマン

7

これは個人的な意見であることに注意してください。塩の粒でそれを取る。

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

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

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

3
私はこれまで見てきた答えが好きです。私は特にあなたの最初の点が好きです-編集は私の答えで言及しようとしていたことの1つです-^ X ^ Eを使用しても、コマンドで編集するよりもお気に入りのエディタでスクリプトを編集する方がはるかに簡単ではるかに楽しいです-ライン。
cas

2
ポイント4は無意味に見えますが、賛成です。:)
アンソニーG-モニカの正義

@cas:control-arrow-key(またはalt + f / alt + b)を使用すると、1行で非常に高速に移動できます。特に、キーの自動リピート設定が50 /秒などであり、220msのような短い遅延が発生する場合。ワンライナー内でcontrol-s / control-r isearchを使用することもできますが、それによって他の履歴に戻ることができます。control-w、alt + backspace、alt + d、control-yが得意であれば、キーボードカーソルを動かすだけで多くのことができます。
ピーターコーデス

また、IIRCの一部のシェル(ZSHなど)には、現在のコマンドラインでエディターを呼び出すキーバインドがあり、お気に入りのエディターで「ワンライナー」を作成し、コマンド履歴に簡単に追加して、矢印と編集。(再実行のために変更できることは、ワンライナーを優れたものにしているのに対して、スクリプトのコマンドラインオプションを処理するためです。)IIRCには外部編集もありますが、デフォルトでは何にもバインドされていません。
ピーターコーデス

@PeterCordesがカーソルを非常に高速に移動しても、vi / vimのような適切なエディターでできることとは比較し始めません。ところで、^ X ^ Eはbashで$ EDITORまたは$ VISUALを呼び出します(他のいくつかのシェル。zshも構成可能だと思います)。改行とインデントを挿入することで、私が作成した読み取り不可能な混乱をわかりやすいものに変える良い方法です-入れ子になったブレースやブラケットがないと、簡単に迷子になります。ところで、私のターミナルウィンドウは250文字以上の幅があるので、折り返さなくてもワンライナーは非常に長くなります。
CAS

7

ワンライナーを一時的な開発ツールとして表示して使用し、必要な処理を繰り返すまで繰り返し編集したり、サブコマンドの微妙な動作を理解したりします。

その後、調査対象のテキストファイルに記録(および注釈)されるか、個人用ビンPATHに追加されたスクリプトにクリーンアップされ、さらに洗練、パラメーター化などが行われます。通常、他の変更が行われなかったり、スクリプトを二度と使用しない場合でも、1行は読みやすいように分割されます。

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

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


1
+1ワンライナーは、上矢印と編集に最適です。vsスクリプトのコマンドラインオプションを実装して、スクリプトの動作とは別に実行することを制御します。たとえば、一部のファイルをループするワンライナーのハードリンクとソフトリンクの変更lnln -s
ピーターコーデス

5

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

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

これは、プログラミングに使用される言語に関係ありません。

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

自宅では、あなたが好きなことをします。

例えば、私はすぐに私が何かやるようスクリプト記述非自明の U&Lの質問に対する答えを提出する前と同様に、シェルでは、または私がのために、「それを実行する前に、コマンドまたはコマンドセットの個々のコンポーネントをテストする必要があるときリアル"。

また、繰り返しタスクのスクリプトを作成します。単純な場合でも、毎回同じ方法で実行したいのです。

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

対話型シェルの利便性のために、シェル関数(非常にまれなエイリアス)を使用します。たとえば、既定で特定のコマンドにオプションを追加する(-Ffor ls)、または一部のコマンドの特殊なバリエーションを作成する(pmanここでは、manPOSIXマニュアルのみを見るコマンドなど) 。


5

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

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

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

管理者のチームがいる場合、最も簡単なのvim /root/bin/x.shは、変更関連のコミュニケーション、コードの読みやすさ、システム間の分散という点で、ほとんどが災害です。多くの場合、1つの重大な誤動作には、「重い」と思われるプロセスよりも多くの時間/お金がかかります。

私は実際にその「重い」プロセスに値しないものにはワンライナー好む。シェルの履歴を効果的に使用する方法を知っていれば、いくつかのキーストロークでそれらを迅速に再利用できます。関係のないシステム(異なる顧客など)間に簡単に貼り付けられます。

(未レビュー!)ワンライナーとレビュー済みソフトウェア(「スクリプト」)の重要な違い:ワンライナーを実行するときの責任はユーザーにあります。あなたは「何続くことは私のせいではありませんが、私は理解せずにそれを実行した、私はちょうどこのワンライナーのどこかを見つけ、」自分自身に言うことはできません-あなたはそれはあなたが、未審査およびテストされていないビット・オブ・ソフトウェアを実行している知っているあなたのせい。結果を予測できるほど小さいことを確認してください-そうでない場合はのろわれます。

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


1
良い点:「スクリプト」よりも「プログラム」という用語が好きです。
グレンジャックマン

5

私は、質問の最初の部分の意味に幾分ぞっとしていると言わなければなりません。Unixスクリプト言語は本格的なプログラミング言語であり、プログラミング言語は言語です。つまり、人間の言語と同じくらい無限に順応性と柔軟性があります。また、「無限の柔軟性と柔軟性」の特徴の1つは、何かを表現する「正しい方法」はほとんどないということです。さまざまな方法があり、これは良いことです。だから、はい、もちろんそれは個人の好みの問題だ、と何も間違ったことはしてあります。何かをする唯一の方法があると言う人は誰でも、

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

スクリプトの作成に問題はないと思います。あなたまたは他の誰かが再びそれを使用するかもしれないと想像するなら、必ずスクリプトを書いてください。サポートのためにサポート可能なスクリプトを「適切に設計」したい場合は、ぜひ行ってください。(たとえ誰も使用していなくても、書くことは良い習慣です。)

スクリプトをあまり記述しない理由(そして、「ワンライナー」を好む)。

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

4

私はほとんどの場合、「ワンライナー」のリクエストは実際には「サウンドバイト」のリクエストであると信じています。

ジャーナリズムの文脈では、サウンドバイトは、話者が言おうとしていることの本質を捉えた短いフレーズまたは文によって特徴付けられ、情報を要約するために使用されます...

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

場合によっては、スピーチを「サウンドバイト」に減らす方法がなく、スクリプトを短い「ワンライナー」に減らすことは不可能な場合があります。そのような場合、唯一の可能な答えはスクリプトです。

そして、一般的に、「サウンドバイト」はスピーチ全体の良い代用になることはありません。そのため、「1つのライナー」は一般に、アイデアを伝えるか、そのアイデアの実際的な例を示すのに適しています。次に、アイデアが理解された後、スクリプトで展開(適用)する必要があります。

そのため、アイデアやコンセプトを伝える「ワンライナー」を作成します。

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


1

「スクリプトの恐怖と軽da」について尋ねます。これはQ + Aの状況によるもので、多くの場合、答えは次のとおりです:このステップとこれが必要ですが、1行で入力することもできます(コピーして貼り付けて、長い単純なコマンドとして使用できます)。

Qが素早い汚れたコピーペーストソリューションによってより適切に処理されるかどうか、または「素敵な」スクリプトがQが理解する必要のあるものであるかどうかしか推測できない場合があります。

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

シェル履歴ファイルは「1つのライナー」ですが、まだ保存されています。bash関数operate-and-get-next (C-o)を使用すると、それらを半自動的に繰り返すこともできます。

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

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

関数も同様の方法で定義する必要があります。手始めに、thisfunc() {...}ホームディレクトリに「functions」というファイルを入れ、それを入手します。はい、これはいくらかのオーバーヘッドですが、一般的なソリューションです。

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

ワンライナーには、それ自体が迅速で汚いものは何もありません。コピーペーストの部分に少し眉をひそめ、コマンドヒストリに依存して保存する方法です。


@sitaram:あなたの1人のライナーは本当に非独創的な機能を持ってます:シバンライン、改行、4つのユーティリティ呼び出し-それらの2つは「プログラム」をsedしました。オリジナルのperlスクリプトは見栄えが良く、より速く実行され、60行に広がることでバイトを浪費しなかったと思います。また、perlを使用すると、かなり絞ることができます。

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


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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.