web-dev-qa-db-ja.com

Pythonで一般的なbashイディオムを実装する方法は?

現在、テキストファイルの操作は、覚えの悪いAWK、sed、Bash、およびごく一部のPerlを使用して行っています。

私はpythonがこの種のものに適しているといういくつかの場所に言及しているのを見ました。 Pythonを使用して、シェルスクリプト、AWK、sed、およびフレンドを置き換えるにはどうすればよいですか?

242
Chris Jefferson

シェルにはいくつかの機能セットがあります。

  • Essential Linux/Unixコマンド。これらはすべて subprocess ライブラリから利用できます。これは、all外部コマンドを実行するための常に最良の最初の選択肢とは限りません。個別のLinuxコマンドである一部のコマンドについては shutil もご覧ください。ただし、Pythonスクリプトに直接実装することもできます。 Linuxコマンドの別の巨大なバッチは os ライブラリにあります。これらはPythonでより簡単に行うことができます。

    そして、ボーナス! -より迅速に。シェル内の個別のLinuxコマンド(いくつかの例外を除く)は、サブプロセスをフォークします。 Python shutilおよびosモジュールを使用することにより、サブプロセスをフォークしません。

  • シェル環境機能。これには、コマンドの環境を設定するもの(現在のディレクトリと環境変数、その他)が含まれます。これはPythonから直接簡単に管理できます。

  • シェルプログラミング機能。これはすべて、プロセスステータスコードのチェック、さまざまなロジックコマンド(if、while、forなど)、テストコマンド、およびそのすべての関連コマンドです。関数定義のもの。これはすべてPythonではるかに簡単です。これは、bashを削除してPythonで実行した場合の大きな勝利の1つです。

  • インタラクション機能。これには、コマンド履歴とその他が含まれます。シェルスクリプトを記述するためにこれは必要ありません。これは人間の相互作用のためだけであり、スクリプト作成のためではありません。

  • シェルファイル管理機能。これには、リダイレクトとパイプラインが含まれます。これは難しいです。この多くはサブプロセスで実行できます。しかし、シェルで簡単に実行できることは、Pythonでは不快です。特に(a | b; c ) | something >resultのようなもの。これは、2つのプロセスを並行して実行し(aの出力をbへの入力として)、続いて3番目のプロセスを実行します。そのシーケンスからの出力はsomethingと並行して実行され、出力はresultという名前のファイルに収集されます。他の言語で表現するのは複雑です。

特定のプログラム(awk、sed、grepなど)は、多くの場合Pythonモジュールとして書き換えることができます。船外に出ないでください。必要なものを置き換えて、「grep」モジュールを進化させます。 「grep」を置き換えるPythonモジュールを書くことから始めないでください。

最も良いのは、これを段階的に実行できることです。

  1. AWKとPerlをPythonに置き換えます。他のすべてを放っておきます。
  2. GREPをPythonに置き換えることを見てください。これはもう少し複雑になりますが、GREPのバージョンは処理のニーズに合わせて調整できます。
  3. FINDをos.walkを使用するPythonループに置き換えることを見てください。プロセスをそれほど多く生成しないので、これは大きな勝利です。
  4. 一般的なシェルロジック(ループ、決定など)をPythonスクリプトに置き換えることを検討してください。
144
S.Lott

はい、もちろん :)

あなたを助けるこれらのライブラリを見てくださいShellスクリプトを再び書くことはありません(Plumbumのモットー)。

また、awk、sed、grepをPythonベースのものに置き換える場合は、 pyp -をお勧めします

「The Pyed Piper」、またはpypは、awkまたはsedに似たLinuxコマンドラインテキスト操作ツールですが、標準のpython文字列およびリストメソッド、およびカスタム関数を使用して進化し、厳しい生産環境。

103
Piotr Dobrogost

Bashとipythonの最良の部分を組み合わせる方法を発見しました。今までは、これはサブプロセスなどを使用するよりも快適なようです。既存のbashスクリプトの大部分を簡単にコピーできます。 python方法でエラー処理を追加します:)そして、ここに私の結果があります:

#!/usr/bin/env ipython3

# *** How to have the most comfort scripting experience of your life ***
# ######################################################################
#
# … by using ipython for scripting combined with subcommands from bash!
#
# 1. echo "#!/usr/bin/env ipython3" > scriptname.ipy    # creates new ipy-file
#
# 2. chmod +x scriptname.ipy                            # make in executable
#
# 3. starting with line 2, write normal python or do some of
#    the ! magic of ipython, so that you can use unix commands
#    within python and even assign their output to a variable via
#    var = !cmd1 | cmd2 | cmd3                          # enjoy ;)
#
# 4. run via ./scriptname.ipy - if it fails with recognizing % and !
#    but parses raw python fine, please check again for the .ipy suffix

# ugly example, please go and find more in the wild
files = !ls *.* | grep "y"
for file in files:
  !echo $file | grep "p"
# sorry for this nonsense example ;)

システムシェルコマンド および使用方法 システムシェルとして のIPythonドキュメントを参照してください。

57
TheK

2015年およびPython 3.4のリリースの時点で、合理的に完全なユーザーインタラクティブシェルが利用可能になりました。 http://xon.sh/ または https:// github.com/scopatz/xonsh

デモビデオ は使用されているパイプを表示しませんが、デフォルトのシェルモードの場合はサポートされます。

Xonsh( 'conch')はbashをエミュレートするために一生懸命努力します。

env | uniq | sort -r | grep PATH

または

my-web-server 2>&1 | my-log-sorter

それでも正常に動作します。

チュートリアルは非常に長く、一般にアッシュまたはバッシュプロンプトで期待される機能の多くをカバーしているようです。

  • コンパイル、評価、実行!
  • コマンド履歴とタブ補完
  • ?および??のヘルプとスーパーヘルプ
  • エイリアスとカスタマイズされたプロンプト
  • インポート可能なコマンドや*.xshスクリプトを実行します
  • ${}を使用したルックアップを含む環境変数
  • 入力/出力のリダイレクトと結合
  • バックグラウンドジョブとジョブ制御
  • サブプロセス、パイプ、およびコプロセスのネスト
  • コマンドが存在する場合はサブプロセスモード、そうでない場合はPythonモード
  • $()でキャプチャされたサブプロセス、$[]でキャプチャされていないサブプロセス、@()で評価されたPython
  • *を使用したファイル名のグロビング、またはバックティックを使用した正規表現のファイル名のグロビング
44
Kamilion
  • Pythonをシェルとして使用する場合は、 IPython をご覧ください。言語をインタラクティブに学ぶことも良いことです。
  • 大量のテキスト操作を行い、Vimをテキストエディターとして使用する場合は、PythonでVimのプラグインを直接作成することもできます。 Vimで「:help python」と入力し、指示に従うか、この presentation を見てください。エディターで直接使用する関数を書くのはとても簡単で強力です!
31
Mapad

最初はsh、sed、awk(およびfind、grep、...)がありました。良かったです。しかし、awkは奇妙な小さな獣であり、頻繁に使用しないと覚えにくい場合があります。その後、偉大なラクダがPerlを作成しました。 Perlはシステム管理者の夢でした。ステロイドのシェルスクリプトのようでした。正規表現を含むテキスト処理は、言語の一部にすぎません。それからい...人々はPerlで大きなアプリケーションを作ろうとしました。誤解しないでください。Perlはアプリケーションになれますが、本当に注意しなければ混乱のように見えます(できます!)。次に、このフラットデータビジネスがすべてあります。プログラマーを動かすのに十分です。

Python、Rubyなどを入力してください。これらは本当に非常に優れた汎用言語です。それらはテキスト処理をサポートし、それをうまく行います(ただし、おそらく言語の基本的なコアと密接に結びついていません)。しかし、彼らはまた非常にうまくスケールアップし、一日の終わりにはまだ見栄えの良いコードを持っています。彼らはまた、ほとんどすべてのためにたくさんのライブラリを備えたかなり多額のコミュニティを開発しています。

今、Perlに対する否定的な点の多くは意見の問題であり、確かに一部の人々は非常にきれいなPerlを書くことができますが、この多くの人々は難読化されたコードを作成するのは簡単すぎると不平を言うので、あなたはいくらかの真実がそこにあることを知っています。質問は実際になります。単純なbashスクリプトの置換以上にこの言語を使用することはありますか。そうでない場合は、もう少しPerlを学んでください。それは絶対に素晴らしいことです。一方、もっとやりたいように成長する言語が必要な場合は、PythonまたはRubyをお勧めします。

いずれにせよ、幸運を祈ります!

16
MattG

素晴らしいオンラインブックDive Into Pythonをお勧めします。それは私が元々言語を学んだ方法です。

言語の基本構造と多くの有用なデータ構造を教えるだけでなく、 ファイル処理 の章と 正規表現 の章もあります。

9
Dan Lenski

以前の回答に追加:インタラクティブコマンド(adduser、passwdなど)を処理するための pexpect モジュールを確認します

7

Pythonが好きな理由の1つは、POSIXツールよりもはるかに標準化されていることです。各ビットが他のオペレーティングシステムと互換性があることを二重および三重チェックする必要があります。 Linuxシステムで作成されたプログラムは、OSXのBSDシステムでも同じように動作しない場合があります。 Pythonでは、ターゲットシステムに十分に新しいバージョンのPythonがあることを確認するだけです。

さらに良いことに、標準のPythonで書かれたプログラムはWindowsでも実行できます!

7
Hal Canary

ここで、経験に基づいて私の意見を述べます。

シェルの場合:

  • シェルは非常に簡単に読み取り専用コードを生成できます。それを書きなさい、そしてあなたがそれに戻ったとき、あなたは二度と何をしたか分からないだろう。これを実現するのは非常に簡単です。
  • シェルは、パイプを使用して1行で大量のテキスト処理、分割などを実行できます。
  • 異なるプログラミング言語でプログラムの呼び出しを統合することになると、それは最高のグルー言語です。

Pythonの場合:

  • 含まれるウィンドウへの移植性が必要な場合は、pythonを使用します。
  • pythonは、数字のコレクションなど、テキストだけを操作する必要がある場合に適しています。これには、pythonをお勧めします。

私は通常、ほとんどのことでbashを選択しますが、ウィンドウの境界を越える必要があるものがある場合は、Pythonを使用します。

6
Germán Diago

pythonpy は、awkおよびsedの多くの機能に簡単にアクセスできるツールですが、python構文を使用します。

$ echo me2 | py -x 're.sub("me", "you", x)'
you2
4
RussellStewart

このトピックの調査中に、私は この概念実証コード を見つけました( http://jlebar.com/2010/2/1/Replacing_Bash.html のコメント経由) )これにより、「簡潔な構文を使用して、Pythonでシェルのようなパイプラインを記述し、既存のシステムツールを活用することができます」:

for line in sh("cat /tmp/junk2") | cut(d=',',f=1) | 'sort' | uniq:
    sys.stdout.write(line)
3
Nickolay

セミロングシェルスクリプト(300〜500行)と、同様の機能を実行するPythonコードを作成しました。多くの外部コマンドが実行されているとき、シェルの方が使いやすいと思います。 Perlは、多くのテキスト操作がある場合にも適したオプションです。

3
Mike Davis

あなたの最善の策は、あなたの問題に特化したツールです。テキストファイルを処理している場合は、Sed、Awk、Perlが最有力候補です。 Pythonは汎用動的言語です。あらゆる汎用言語と同様に、ファイル操作のサポートがありますが、それはコアの目的ではありません。特に動的言語の要件がある場合は、PythonまたはRubyを検討します。

要するに、SedとAwkに加えて、* nix(Bashのすべてのビルトイン、grep、trなど)のフレーバーに付属する他のすべてのグッズをよく学んでください。興味のあるテキストファイル処理であれば、すでに適切なものを使用しています。

2
Eric Smith

ShellPy ライブラリでは、bashの代わりにpythonを使用できます。

GithubからPythonユーザーのアバターをダウンロードする例を次に示します。

import json
import os
import tempfile

# get the api answer with curl
answer = `curl https://api.github.com/users/python
# syntactic sugar for checking returncode of executed process for zero
if answer:
    answer_json = json.loads(answer.stdout)
    avatar_url = answer_json['avatar_url']

    destination = os.path.join(tempfile.gettempdir(), 'python.png')

    # execute curl once again, this time to get the image
    result = `curl {avatar_url} > {destination}
    if result:
        # if there were no problems show the file
        p`ls -l {destination}
    else:
        print('Failed to download avatar')

    print('Avatar downloaded')
else:
    print('Failed to access github api')

ご覧のとおり、Graveアクセント( `)シンボル内のすべての式はシェルで実行されます。また、Pythonコードでは、この実行の結果をキャプチャし、アクションを実行できます。例えば:

log = `git log --pretty=oneline --grep='Create'

この行は、最初にシェルでgit log --pretty=oneline --grep='Create'を実行してから、結果をログ変数に割り当てます。結果には次のプロパティがあります。

stdout実行されたプロセスのstdoutからのテキスト全体

stderr実行されたプロセスのstderrからのテキスト全体

returncode実行のリターンコード

これはライブラリの一般的な概要です。詳細な説明と例は here にあります。

2

PyPIでパッケージを公開しました: ez
pip install ezを使用してインストールします。

シェルには一般的なコマンドが詰め込まれており、私のlibは基本的にシェルと同じ構文を使用しています。たとえば、cp(source、destination)はファイルとフォルダーの両方を処理できます! (shutil.copy shutil.copytreeのラッパーで、いつどれを使用するかを決定します)。さらにうまく、Rのようなベクトル化をサポートできます!

別の例:os.walkなし、fls(path、regex)を使用してファイルを再帰的に検索し、正規表現でフィルター処理し、フルパスの有無にかかわらずファイルのリストを返します

最後の例:これらを組み合わせて、非常に単純なスクリプトを作成できます。
files = fls('.','py$'); cp(files, myDir)

間違いなくチェックしてください!書く/改善するのに何百時間もかかりました!

1
Jerry T

テキストファイルの操作が通常1回であり、シェルプロンプトで行われる場合は、pythonから何も改善されません。

一方、同じ(または同様の)タスクを何度も繰り返し行う必要があり、そのためのスクリプトを記述する必要がある場合、pythonは素晴らしいです。独自のライブラリ(シェルスクリプトでも同様に行えますが、より面倒です)。

感覚をつかむための非常に簡単な例。

import popen2
stdout_text, stdin_text=popen2.popen2("your-Shell-command-here")
for line in stdout_text:
  if line.startswith("#"):
    pass
  else
    jobID=int(line.split(",")[0].split()[1].lstrip("<").rstrip(">"))
    # do something with jobID

Sysとgetoptモジュールもチェックしてください。最初に必要です。

1
Davide