- Linux Mint を始めたばかりの人が抑えておくべき5つのこと
- 「mintUpdate」アップデートマネージャー のレベルの意味
- フリーズしたアプリの強制終了の仕方 〜 kill コマンド〜
- CPU と OS が 32 bit なのか 64 bit なのかを確認する「lscpu コマンド」
- メモリー(RAM)の規格・周波数・全容量・空き容量・エラーの有無を調べる
- 自分の Mint のバージョン/コードネーム/Ubuntu のバージョン/コードネームを確認する方法
- Mint Tools を使い倒す
- アプリ/ソフトのアンインストールと更新する方法
- X-Apps について少し知っておこう
- 「'gksu' not found」 廃止された gksu の代わりの方法
- Linux Mint 18 : DVD/Blu-ray リッピングソフト「MakeMKV」
- Mint 19.x: 「K3b」でブルーレイディスクに焼く方法
- Mint 18: 「avconv」でデスクトップの録画も、動画や音楽の変換も行う
- Mint 19.x : 画像・音楽・動画の変換これ一本「Ciano」
- Mint 18.2 : 字幕を同時に二つ表示できる多機能な動画プレイヤー「SMPlayer」
- Mint 18 : CDDB に Freedb を利用している CD リッピングソフト「Asunder」
- Mint 19.x : 音楽ファイルのタグ編集ツール「Kid3」
- Linux Mint 19.x : インストールすべき Rhythmbox プラグイン 9 選
- Linux Mint 18.3 : VirtualBox に無料の Windows を合法的にインストールする方法
- Linux Mint 18: Wine の導入
- Linux Mint 18: Wine で「DVD Shrink」をインストール
- Linux Mint 18: Wine で「DVD Decrypter」をインストール
- Linux Mint 19.x: 5ch専ブラ「Jane Style」は Wine で普通に使える
- Linux Mint 18 : 「winetricks」を使って「Adobe Air」をインストールし「はがきデザインキット」を使う
- Linux Mint 19.x: 画像縮小 Adobe AIR アプリ「縮小専用」を使う
- Linux Mint 18: 「PlayOnLinux」を使い「Amazon Kindle」をインストールする
- Linux Mint 18.3 : ハイレゾ音源対応 Windows ユーザーに人気の「Foobar2000」をインストール & 文字化け対策
- Mint 19.x : 画像ビューア「IrfanView」を簡単にインストールして使う
- Linux Mint 18.3 : Windows アプリを Flatpak 形式でパッケージングするプロジェクト「winepak」
2022.09.19 Monday
2019.03.01 Friday
Shell :シェルスクリプトを組もう! Dialog 編 | 08:00 |
Zenity よりはあまり知られていないかもしれませんが、シェルスクリプトの中でダイアログボックスを表示するのに使えるユーティリティーは他にもたくさんあり、今回は「dialog」を紹介します。dialog を使ってシェルスクリプトに GUI (的な要素)を組み込む方法を見ていきます。
dialog は以下の 8 種類のボックスを作ることができます:
- はい/いいえボックス
- メニューボックス
- 入力ボックス
- メッセージボックス
- テキストボックス
- 情報ボックス
- チェックリストボックス
- ラジオリストボックス
以下のコマンドはタイトルに「通知」、メッセージに「プログラムを開始します。」という 5 行分の高さと半角 30 文字分の横幅を持つメッセージボックスを表示します:
dialog --title "プログラムの開始" --msgbox "プログラムを開始します。" 5 30
基本的にダイアログボックスは dialog、続いてタイトル(オプション)、続いてボックスの種類、続いて表示したいメッセージ、最後にサイズを指定します。
次のコマンドでは <はい>・<いいえ> のボタンが下部に表示されます。<はい> が押されると 0 を返し、<いいえ> が押されると 1 を返します:
dialog --title "プログラムの続行" --yesno "プログラムを続行しますか?" 5 35
response=$?
case $response in
0) echo "はいが押されました";;
1) exit 0 ;;
esac
ダイアログボックスのサイズが小さすぎると文字が隠れてしまうので注意してください。
最初にメッセージボックスを見ましたが、インフォボックスも似たようなボックスです。違う点は、了解ボタンが無い点です:
dialog --infobox "しばらくお待ちください。" 10 30 ; sleep 4
入力ボックスはユーザーに文字列を入力させることができます。編集キー(恐らくバックスペースキーやデリートキーなどのことだと思います)も使用できます。テキストフィールドは必要な時スクロールします。データが入力された後、Stream 2 ("STDERR") に出力されますが、より一般的にはファイルに出力をリダイレクトして使います:
dialog --inputbox "ユーザー名は?:" 8 40 2>answer
return=$(cat answer)
echo $return
rm -f answer
テキストボックスはシンプルなファイルビューアーで、パラメータにファイル名を指定します。ここでは矢印キーや
Page Up
Page Down
Home
などが使えます。ESC
あるいはEnter
で抜け出せます:dialog --textbox /etc/profile 22 70
メニューは選択肢を表示し、ユーザーにどれか選ばせることができます。構文は以下の通りです:
dialog --menu "文字列" 高さ 幅 選択肢の数 1 選択肢1 2 選択肢2 3 選択肢3
ユーザーは矢印キーで移動した後、
Enter
を押すことで選択できます。Stream 2 ("STDERR") に出力されます。例えばこのような感じで使います:dialog --menu "一つ選んでください:" 10 30 3 1 赤 2 緑 3 青 2>temp
return=$(cat temp)
echo "あなたが選んだのは:"$return
rm -f temp
チェックリストではユーザーに選択肢のリストを表示しスペースで個別に ON/OFF を切り替えることができます。三つ目のフィールドにはデフォルトの ON/OFF を設定します:
dialog --checklist "使ったことのあるデスクトップ環境を選んで下さい:" 13 40 3 \
1 "Cinnamon" on \
2 "MATE" on \
3 "Xfce" off 2>temp
最後にラジオリストを取り上げます。基本的にはチェックリストと同じですが、ユーザーが選べるのは一つだけという違いがあります:
dialog --backtitle "Game Console Selection" \
--radiolist "一番好きなゲーム機は:" 10 40 4 \
1 "XBox One" off \
2 "Play Station 4" on \
3 "Nintendo Switch" off \
4 "Nintendo DS 3" off 2>temp
実際にスクリプトを組んでみる
北陸先端科学技術大学院大学のミラーサーバーから指定の Linux Mint 19.1 64bit をダウンロードするスクリプトです。簡単なスクリプトですが雰囲気はつかめると思います:
#!/bin/sh
dialog --backtitle "ダウンロードしたいエディションをえらでください:" --radiolist "一つ選んでください:" 10 40 3 1 "Cinnamon 64bit" on 2 "MATE 64bit" off 3 "Xfce 64bit" off 2>temp
# OK が押されたら
if [ "$?" = "0" ]
then
_return=$(cat temp)
# 1 を選んだ時
if [ "$_return" = "1" ]
then
url="http://ftp.jaist.ac.jp/pub/Linux/linuxmint/isos/stable/19.1/linuxmint-19.1-cinnamon-64bit.iso"
fi
# 2 を選んだ時
if [ "$_return" = "2" ]
then
url="http://ftp.jaist.ac.jp/pub/Linux/linuxmint/isos/stable/19.1/linuxmint-19.1-mate-64bit.iso"
fi
# 3 を選んだ時
if [ "$_return" = "3" ]
then
url="http://ftp.jaist.ac.jp/pub/Linux/linuxmint/isos/stable/19.1/linuxmint-19.1-xfce-64bit.iso"
fi
# キャンセルが押されたら
else
echo "取消が押されました。"
fi
dialog --menu "保存先を選んでください" 10 30 3 1 /tmp 2 ~/ダウンロード 3 ~/デスクトップ 2>temp
# OK が押されたら
if [ "$?" = "0" ]
then
_return=$(cat temp)
# /tmp を選んだ時
if [ "$_return" = "1" ]
then
wget "$url" -P /tmp
fi
# ~/ダウンロードを選んだ時
if [ "$_return" = "2" ]
then
wget "$url" -P $HOME/ダウンロード
fi
# ~/デスクトップを選んだ時
if [ "$_return" = "3" ]
then
wget "$url" -P $HOME/デスクトップ
fi
# キャンセルが押されたら
else
echo "取消が押されました。"
fi
# temp ファイルの削除
rm -f temp
参考元: Linux Journal
| プログラミング |
2019.01.06 Sunday
Shell :シェルスクリプトを組もう! Zenity 編 | 01:44 |
イントロ
例えば、あなたがゲーム開発者であったとしましょう。開発の過程で、テクスチャアトラスから座標を取得しゲームコードに記述する作業があります。ん?何を言っているか分かりませんか。テクスチャアトラスとは下の画像のように、一つのキャラクター(別に複数でも可)に対して全ての部品をまとめ画像のことを指します。一つのポーズにつき一枚の画像を用意するのは効率が悪いため、ゲーム開発やウェブサイトの画像の読み込みなどでよく使われる手法です:
このテクスチャアトラスから切り取りたい部分を座標で指定する必要が出てくるのですが、座標を指定するのに 4 つの数字を覚える必要が有り、疲れているときは覚えることが出来ず、一つ一つ数字を確認しながら、
Alt
+Tab
で画像編集ソフトとテキストエディターを行き来します:もし、テキストボックスがあるポップアップウィンドウをショートカットキーで表示させ、その中に入力した文字列が直接クリップボードに保存され、2つのアプリをいちいち切り替える必要なく座標をテキストエディターに入力できたら素敵だと思いませんか。
何が言いたいのかアニメーション GIF で示したいと思います:
Unix の哲学
何か効率化したいと思ったら、Unix の哲学を思い出しましょう:
- 各プログラムが一つのことをうまくやるようにせよ。
- プログラムは組み合わせて作れ。
- 単純なテキストファイルにデータを格納せよ。
つまり、あなたが望んでいることをしてくれるプログラムは、すでに存在する小さなプログラム(コマンド)を組み合わせることで実現できる可能性がとても高いということです。
クリップボードに文字をコピーするコマンド
端末を起動し xsel というクリップボードにコピーしたり、クリップボードの中身を取得したりできるパッケージをインストールしてみて下さい:
sudo apt install -y xsel
次のコマンドを実行してみてください:
echo "ここがコピーされます。" | xsel --clipboard
そしたら、テキストエディターなどにクリップボードの中身を貼り付けてみましょう。
ここがコピーされます。と入力できたはずです。echo の出力をパイプで xsel に渡してクリップボードにコピーしたのです。上述した Unix の哲学に帰れば、なぜ Bash があのように醜く、それでいてこのように素晴らしいものなのか分かるのではないでしょうか。誰かがすでにクリップボードにコピーするという機能を持った小さなプログラムを作成してくれているので、自分で 1 から作る必要がありません。
簡易 GUI アプリの作成
自分が初めて Zenity に出会った時、なんて賢く、なんてシンプルなんだろうと驚きを隠せませんでした。たった一行の文字列ベースの Bash スクリプトが便利な GUI アプリに変貌するのです。
ここで必要とするパーツはエントリーボックスです。エントリーボックスは文字列を入力するためのパーツです。端末で以下を実行してみてください:
zenity --entry
入力した文字列が戻り値として返されます。zenity の戻り値を xsel に渡せば、必要としているものが完成しそうです。
小さなプログラムにまとめる
端末で以下を実行しましょう:
zenity --entry | xsel --clipboard
見事です。最後に、スクリプトにまとめて、実行権限を付加し実行してみましょう。以下のコマンドはそれらのすべてを行います:
echo -e '#!/bin/bash' > handy-clipboard.sh && echo 'zenity --entry | xsel --clipboard' >> handy-clipboard.sh && chmod +x ./handy-clipboard.sh && ./handy-clipboard.sh
完成です。Unix の哲学の恩恵を得て、Unix の哲学に貢献するような小さなプログラムを作り上げたのです。
値を取得する
zenity --entryで表示されるダイアログに入力される文字列をクリップボードではなく、プログラムの中で使いたい場合はどうすればよいでしょうか。以下を実行してみて下さい:
x=$(zenity --entry)
echo $x
入力した文字列が端末に表示されましたか?
つまり、
変数名=$(zenity のコマンド)という書式になっています。使うときは
$変数名というふうに $ マークを変数名の前につけるだけで OK です。
しかし、もっと簡潔な方法があります。次のコマンドは上のものとほぼ同じ結果をもたらします:
zenity --entry; echo $?
これらのダイアログボックスを抑えておけば大丈夫
入力
今まで、エントリーボックスを使ってきましたが、--title でボックスのタイトルを、--text で文字を添えることができます:
zenity --entry --title "質問" --text "アニメキャラクターは誰が好きですか?"
初期値を表示するには --entry-text を使います:
zenity --entry --title "質問" --text "アニメキャラクターは誰が好きですか?" --entry-text "初音ミク"
質問
質問内容が Yes か No で答えられるようなものであればこちらが用意されています:
zenity --question --text "初音ミクは好きですか" --ok-label "大好きです" --cancel-label "好きです"
zenity --question ダイアログでは
- OK なら 0
- Cancel なら 1
- タイムアウトなら 5
case $? in
0) echo "Yes"
;;
1) echo "No"
;;
*) echo "Timeout"
;;
esac
if 文で 1 であれば即プログラムを終了させたりできるわけです:
if [ $? == 1 ]; then exit; fi
メッセージ・通知
その際、エラーとして終了するのであれば以下のようなメッセージボックスが作れます:
zenity --error --title "エラー" --text "プログラムを実行中エラーが発生しました。プログラムを終了します。"
単に終了するよと言いたければ --info が良いかもしれません:
zenity --info --title "終了" --text "キャンセルが押されたので終了します。"
警告として表示する場合は --warning を使います:
zenity --warning --title "終了します" --text "終了すると入力された値は破棄されます。"
メッセージをウィンドウではなく、通知としてそれとなく表示させたい場合はこうします:
zenity --notification --text "処理が終わりました。"
色を付けるときは html タグで
表示する文字に色を付けることができます。その時は html タグと同様の使い方をします:
zenity --info --text "
<span color=\"red\">red</span>
<span color=\"green\">green</span>
<span color=\"blue\">blue</span>
<span color=\"yellow\">yellow</span>
<span color=\"magenta\">magenta</span>
<span color=\"white\">white</span>
<span color=\"black\">black</span>
<span color=\"gray\">gray</span>
<span color=\"lightblue\">lightblue</span>
<span color=\"lightgray\">lightgray</span>"
目盛り
入力される値は文字列だけとは限りません。数値のときもあるでしょう。便利なダイアログが用意されています:
val=$(zenity --scale --text "1 から 30 までの値を選んで下さい。" --min-value 1 --max-value 30 --value 20 --step 1)
echo "入力された値は "$val" です。"
カレンダー
数値は数値でも日付であれば --calendar を使います:
date=$(zenity --calendar --text "日付を選んで下さい。")
echo "$date"
リスト
はじめから用意された項目から選んでほしいときは --list を使います:
extension=$(zenity --list --title "拡張子を選んで下さい" --text="拡張子を選んで下さい。" --column "拡張子" MOD mp4 avi mpg mkv mov MOV)
echo $extension
カラムは増やせます:
extension=$(zenity --list --title "拡張子を選んで下さい" --text="拡張子を選んで下さい。" --column "拡張子" --column "音楽・映像" mp4 映像 avi 映像 mpg 映像 acc 音楽 mp3 音楽)
echo $extension
リストでチェックボックスを使用できます(True or False はデフォルトでチェックを入れるか入れないかを示しています):
zenity --list --checklist --column "チェック" --column "ペット" True 犬 False 猫 True ハムスター
ラジオボタンも同様に可能です(True or False はデフォルトでチェックを入れるか入れないかを示しています):
zenity --list --radiolist --column=Selected --column "ペット" False 犬 False 猫 True ハムスター
ファイルチューザー
ファイルを選んでほしいときは --file-selection を使います。これだけだとファイルを指定できます:
file=$(zenity --file-selection --text "ファイルを選んで下さい。")
echo "$file が選ばれました。"
--directory を追加すれば選べるのはディレクトリだけになります:
folder=$(zenity --file-selection --directory --title "ディレクトリを選んで下さい")
echo $folder
--multiple を追加すれば複数指定できるようにできます:
files=$(zenity --file-selection --multiple --text "ファイルを複数選んで下さい。")
echo "$files が選ばれました。"
保存先用のダイアログも表示できます:
zenity --file-selection --save
フォーム
フォームもこのように作成できます:
zenity --forms --add-entry "ユーザー名" --add-password "パスワード" --separator ","
user=$(zenity --forms --add-entry "ユーザー名" --add-password "パスワード" --separator ",")
echo $userとしたときに、例えばユーザー名に「初音ミク」、パスワードに「pass」と入力し [ OK ] を押せば、以下の結果が返ってくるはずです:
初音ミク,pass
つまり --separator で指定した文字(ここでは ,)で仕切られた文字列が返ってきます。入力された値を使うにはどうにかして「,」で切り分ける必要があります:
username=$(awk -F, '{print $1}' <<<$user)
password=$(awk -F, '{print $2}' <<<$user)
これで、それぞれの値が $username と $password に格納されます。
プログレスバー
プログレスバーも実装できますが、少し難しいです。まず基本的には以下のとおりです。--percentage は 0 から 100 までの値を取ることができます:
zenity --progress --percentage=10
具体的にどれくらいと表示するのが難しいかも知れません。そのときは左右行ったり来たりするバージョンを使うといいでしょう:
zenity --progress --pulsate
100% になったときプログレスバーが自動的に消えてほしい場合は --auto-close を追加します:
zenity --progress --auto-close
1 から 10 まで数えてその分増えていくプログレスバーはこのようになります:
percent=0;
for num in 0 1 2 3 4 5 6 7 8 9 10; do
echo $percent
echo "# $num"
percent=$(($percent + 10));
sleep 1
done | zenity --progress --text "Counting..." --percentage=0
複数行に渡る文字列を表示する
--text-info はテキストファイルから表示したい内容を読み込むときに使います。以下の例では GPLv3 のライセンスを表示します:
zenity --text-info --filename "/usr/share/common-licenses/GPL-3"
テキストエリアのように編集できるエリアにしたい場合は --editable をつけます:
zenity --text-info --editable
カラーパレット
使う機会はそこまでないかも知れませんが、カラーパレットも表示できます:
color=$(zenity --color-selection --show-palette)
汎用性のあるパラメーター
次のパラメーターは上述した大抵のウィジェットで使えます:
- --title "タイトル"
- --height 400
- --width 300
- --icon-path "/usr/share/icons/Mint-X/categories/32/gnome-multimedia.png"
例えば、先程出したこのエラーメッセージは少々不格好です:
そこで幅を指定することでスッキリさせることができます:
zenity --error --width 350 --title "エラー" --text "プログラムを実行中エラーが発生しました。プログラムを終了します。"
音楽ファイル変換スクリプトを組んでみる
ここからは ffmpeg と zenity の力を借りて音楽を変換する簡易的なスクリプトを作成していきます。FFmpeg がインストールされていなければして下さい:
sudo apt install -y ffmpeg
#!/bin/bash
#変換するファイルを選ぶ
source=$(zenity --file-selection --title "変換するファイルを選んで下さい")
echo $source
#ユーザーがキャンセルするか閉じたらスクリプトを終了する
if [ $? == 1 ]; then exit; fi
#変換先のファイル形式を尋ねる
ext=$(zenity --list --title "変換先のファイル形式を選んで下さい" --text "変換先のファイル形式を選んで下さい" --column "拡張子" mp3 ogg flac wav)
echo $ext
#ユーザーがキャンセルするか閉じたらスクリプトを終了する
if [ $? == 1 ]; then exit; fi
#出力先を尋ねる
dest=$(zenity --file-selection --directory --title "出力先を選んで下さい")
echo $dest
#ユーザーがキャンセルするか閉じたらスクリプトを終了する
if [ $? == 1 ]; then exit; fi
#ファイル名を拡張子抜きで取得
filename=$(basename -- "$source")
filename="${filename%.*}"
ffmpeg -i "$source" -ab 320k -map_metadata 0 -id3v2_version 3 "$dest"/"$filename"."$ext"
zenity --notification --text "処理が終わりました。"
簡単に作ったので複数のファイルを指定したりはできないですが、立派に GUI アプリを作れた感じがします:
利便性を良く
このままでは端末からスクリプトを実行しないといけなくなるので、ショートカットキーに割り当てましょう。ミントメニューから [ キーボード ] -> [ ショートカット ] -> [ カスタムショートカット ] -> [ カスタムショートカットを追加 ]:
ショートカットキーの割当は [ 未割り当て ] をクリックして希望のショートカットキーの組み合わせを押します。例えば
Ctrl
+Alt
+F
にしました:これで
Ctrl
+Alt
+F
を押すことでいつでもスクリプトを走らせることができます。Linux 文化は手作り文化
zenity によって簡単なやりとりなら GUI でできることを示しました。シェルスクリプトと ffmpeg や youtube-dl などのコマンドとこの zenity を組み合わせれば、簡単な GUI アプリが作れてしまうわけです。zenity の存在は(クロスプラットホームに対応しているとは言え)間違いなく Linux を使う理由の一つとなるはずです。
参考元 : medium.com, YouTube
| プログラミング |
2018.04.07 Saturday
Linux Mint 18.3 : Python ではじめるコマンドラインツールの作成とパッケージ化 | 02:32 |
今回、Python でシンプルなコマンドラインツールを作成していくにあたり、pokéapi という、番号でポケモンに関する様々な情報を取得できる REST API を使用します。コマンドラインツールの名前は「pokepy」とし、番号を指定すると、ポケモンの名前、タイプ、特性を返してくれるツールを作成します。タイプや特性の id はその番号のポケモンのタイプと特性を表しているわけではなく、タイプや特性特有の id であることに留意してください。構文は以下のような感じになります:
pokepy (pokemon|type|ability) (--id|-i)=<数字>
サンプルは GitHub にアップロードしています:
ShellingfordX/pokepy: A pokeapi wrapper command line tool
使用するモジュール
コマンドラインツールのオプションをパースするモジュール docopt と HTTP リクエストを送信するためのモジュール requests を使います。コマンドのオプションをパースするモジュールには argparse もありますが、大きな違いは argparse が使用するコマンドのオプションを定義するとヘルプが自動生成されるのに対して、docopt はヘルプを書くことによってコマンドのオプションを自動生成してくれる点です。
もし、argparse で pokepy の引数・オプションを解析しようとすると以下のようになります:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import argparse
parser = argparse.ArgumentParser(description='A simple command line tool that shows pokemon info', version='0.1.0') #パーサーオプジェクトを作成します
parser.add_argument('uri', help='Specify pokemon, type or ability') #位置引数
parser.add_argument('-i','--id', type=int, nargs=1, default=1, help='Specify a pokemon number') #オプション引数
args = parser.parse_args() #引数・オプションを解析します
print "番号:",args.id,"¥n","pokemon? type? ability?:",args.uri #表示しています
実行例:
./pokepy.py pokemon --id 25
実行結果:
番号: [25]
pokemon? type? ability?: pokemon
少し説明を加えると、位置引数はハイフンがつかない、必須の引数のことです。これを要求するためにこのコードを書いています:
parser.add_argument('uri', help='Specify pokemon, type or ability') #位置引数
同時に、help='Specify pokemon, type or ability' と書くことで、./pokepy.py -h を実行した時のヘルプに表示するようにしています:
positional arguments:
uri Specify pokemon, type or ability
同様にオプション引数も指定しています。ロング形式の --id とショート形式の -i どちらでも使えるようにし、type=int で受け取る値を数値として読み込み、nargs=1 で渡せる値は 1 つ、default=1 で id の指定がなかった場合に代入される値を指定、最後にヘルプに表示するテキストを指定しています。これはこれで便利ですが、今回はヘルプを書いて、引数を自動生成してくれる docopt を使います:
sudo apt install -y python-docopt
また、python-pip もインストールしておきましょう。今回はコマンドラインツールを作成するだけでなく、作成するスクリプトは pip でインストールするからです:
sudo apt install -y python-pip更に、パッケージ化に setuptools モジュールも使います:
sudo apt install -y python-setuptools
ファイル構成
このプロジェクトに必要な最小構成は次のとおりです:
pokepy/
├── pokepy
│ ├── __init__.py
└── setup.py
ですが、README.rst と MANIFEST.in も追加します:
pokepy/
├── pokepy
│ ├── __init__.py
├── setup.py
├── README.rst
└── MANIFEST.in
これからそれぞれのファイルについて述べていきます。
pokepy/__init__.py
pokepy の機能を実装しているスクリプトです。__init__.py はパッケージ化するにあたり必要なファイルで、import して読み込みたいモジュールがある場合、ディレクトリに含める必要が有ります。初期化のコードを書くか空っぽのままで、機能は別のファイルとして分離するようですが最小構成ということでこのなかに書いてしまいます:
'''
Usage:
pokepy (pokemon | type | ability) --id=ID
Options:
-i --id=ID # specify the id of the pokemon, type or ability
-h --help # Show this help
'''
import requests
POKEAPI = 'https://pokeapi.co/api/v2/{path}/{id}'
def get_api_path(arguments):
'''
Get pokemon or type or ability command from command line
arguments.
'''
paths = ['pokemon', 'type', 'ability']
for path in paths:
if arguments[path]:
break
return path
def get_id(arguments):
'''
Get id from command line arguments.
'''
return arguments['--id']
def call_pokeapi(path, id_number, key='name'):
'''
Call the RESTful PokeAPI and parse the response. If pokemon, ability or
type ids are not found than the error message detail is returned.
'''
url = POKEAPI.format(path=path, id=id_number)
response = requests.get(url)
response_json = response.json()
try:
res = response_json[key]
except:
res = response_json['detail']
return res
def __main__():
'''
Entrypoint of command line interface.
'''
from docopt import docopt
arguments = docopt(__doc__, version='0.1.0')
path = get_api_path(arguments)
id_number = get_id(arguments)
print(call_pokeapi(path, id_number))
docopt
このファイルにはコマンドラインツールのエントリーポイント(プログラムの開始となる位置)を含んでいます。後述する setup.py で __main__ 関数がエントリーポイントとなるよう指定します。端末から実行するとき __main__ 関数が実行されるわけです。最初から数行は docopt を使うために、ドキュメントストリングを記述しています。利用者がこの使用法に従わなかった場合、このドキュメントストリングがヘルプとして表示されます。__main__ 関数内の
from docopt import docoptで docopt モジュールを読み込み、
arguments = docopt(__doc__, version='0.1.0')としてあげることで、端末から入力された引数を参照することができます。この時、「version=数字」も指定してあげることで --version を指定した時に、指定したバージョン(ここでは 0.1.0)が返されます。docopt は内部で sys.argv を使って引数を読み取り、パースしています。パースされた引数は辞書オブジェクトとして返します。なので以下のように値を取り出すことが出来ます:
arguments = docopt(__doc__, version='0.1.0')
arguments['--id']
requests
3つのユーザー定義関数を定義しています。引数から pokemon か type か ability を得る関数(get_api_path)、引数から id を取得する関数(get_id)、GET リクエスト送り JSON データを取得し必要な情報を返す関数(call_pokeapi)の3つです。
response = requests.get(url)で GET リクエストを行い、Requests オブジェクトに対して json() メソッドを使うことで JSON 形式のレスポンスの内容を辞書として扱うことが出来ます:
response = requests.get("https://pokeapi.co/api/v2/pokemon/150/")
response_json = response.json()
print response_json['name']
出力例:
mewtwo
もし、クエリ文字を追加したい場合は以下のようにし params キーワードを使って辞書として引数を渡すことが出来ます:
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://example.org/get", params=payload)
print r.url
出力例:
http://example.org/get?key2=value2&key1=value1
setup.py
パッケージ化(配布可能に)するのに必要なスクリプトです:
from setuptools import setup, find_packages
from codecs import open
from os import path
here = path.abspath(path.dirname(__file__))
# Get the long description from the README file
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
long_description = f.read()
setup(
name='pokepy',
version='0.1.0',
description='A Pokeapi wrapper command line tool',
long_description=long_description,
url='https://github.com/ShellingfordX/pokepy',
author='Shellingford',
author_email='example@gmail.com',
license='Apache 2.0',
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
'License :: OSI Approved :: Apache License',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.5',
],
keywords='Pokeapi REST client wrapper command line interface',
packages=find_packages(),
install_requires=['docopt', 'requests'],
extras_require={ },
package_data={},
data_files=[],
entry_points={
'console_scripts': [
'pokepy=pokepy:__main__',
],
},
)
ちゃんと動作させる上で大事なのは:
install_requires=['docopt', 'requests'],と
entry_points={です。
'console_scripts': [
'pokepy=pokepy:__main__',
]
pip でインストールする必要がある依存関係は install_requires に指定します。エントリーポイント(プログラムの開始点)としてを指定するには、辞書の console_scripts の値として指定します。上の意味は「端末から pokepy を実行したならば、pokepy モジュールの __main__ 関数を呼び出せ」です。classifiers 引数に指定する値は ここ から選びます。
README.md -> README.rst
README.md は GitHub で管理していれば自動生成してくれます。setup.py では long_description の中身に README ファイルを流用していますが、読み込んでいるファイル形式は README.rst です。PyPL が md (マークダウン) 形式には対応していないため、一般的には rst (reStructuredText) 形式を使うのが普通なようです。そこで、md 形式から rst 形式に変換する必要が有ります。変換するには pandoc を使うのが便利です:
sudo apt install -y pandoc
ワーキングディレクトリを README.md がある場所に移し、以下を実行すれば README.md から README.rst を作成することが出来ます:
pandoc -f markdown -t rst -o README.rst README.md
また、Python ファイルでないもので、インストールに含めたいものは MANIFEST.in に指定する必要が有ります:
include README.rst
インストール & 試用
pokepy ディレクトリ内に入り、pip でインストールします。-e は --editable のショート形式で、開発中はソースを編集したい時もあるので、再インストールする必要なく編集できるようにするためのオプションです:
cd pokepy && sudo pip install -e .
Successfully installed pokepyと返されたらインストール成功です。
試しに図鑑番号 25 のポケモンの名前を表示してみます:
pokepy pokemon -i 25
出力例:
pikachu
以上で Python で端末で動く API ラッパーを作成する方法を習得しました。このモジュールをテンプレートにして、より便利でより複雑なツールを作ってはいかがでしょうか。
参考元: Datahovel
| プログラミング |
2009.06.19 Friday
Perl2周目してて、忘れていたこと 4 | 00:30 |
メタ文字$は文字列の終わりにマッチするが
文字列の終わりが改行だったときは
改行の直前にマッチする
結果:Match
改行が複数個あった場合でも
$はあくまで文字列の最後にマッチする
結果:Hello2 -- Match
修飾子/mをつけると
1つの文字列があたかも
改行で区切られた複数の文字列のように振る舞う
結果:Hello1--Match
my $sty="12,13,14";
を,で切り出すには
split(/,/,$str)以外に
ともできる
1回マッチさせたいとき
複数マッチさせたいとき
tooやseeなどにマッチさせたいとき
/http:¥/¥/www¥.example¥.com/
を読みやすくするために
m|http://www¥.example¥.com|
とできる
もっと読みやすくするために
m|¥Qhttp://www.example.com¥E|
とできる
文字列の終わりが改行だったときは
改行の直前にマッチする
if("Hello¥n"=~/Hello$/){
print "Match¥n";
}else{
print "No Match¥n";
}
結果:Match
改行が複数個あった場合でも
$はあくまで文字列の最後にマッチする
if("Hello1¥nHello2¥n"=~/Hello¥d$/){
print "$& -- Match¥n";
}else{
print "No Match";
}
結果:Hello2 -- Match
修飾子/mをつけると
1つの文字列があたかも
改行で区切られた複数の文字列のように振る舞う
if("Hello1¥nHello2¥n"=~/Hello¥d$/m){
print "$&--Match¥n";
}else{
print "No Match¥n";
}
結果:Hello1--Match
my $sty="12,13,14";
を,で切り出すには
split(/,/,$str)以外に
if($str=~/(¥d+),(¥d+),(¥d+)/){
my ($num0,$num1,$num2)=($1,$2,$3);
}
ともできる
1回マッチさせたいとき
if($str=~/¥d+/){
print $&;
}
複数マッチさせたいとき
while($str=~/¥d+/g){
print $&,"¥n";
}
tooやseeなどにマッチさせたいとき
while($str=~/[qwrtyplkjhgfdszxcvbnm]([aeiuo])¥1/g){
print $&,"¥n";
}
/http:¥/¥/www¥.example¥.com/
を読みやすくするために
m|http://www¥.example¥.com|
とできる
もっと読みやすくするために
m|¥Qhttp://www.example.com¥E|
とできる
| プログラミング |
2009.06.08 Monday
PHP:再起的ファイル処理 おまけでディレクトリ下のすべてのmp3をまとめるコード | 19:06 |
//コマンドラインで渡されたディレクトリ下にあるファイルをすべて表示 function recursive_list_files($from="."){ if(!is_dir($from)) return false; $files=array(); if($dh=opendir($from)){ while(false!==($file=readdir($dh))){ if($file=="."||$file=="..") continue; $path=$from."/".$file; if(is_dir($path)) $files+=recursive_list_files($path); else $files[]=$path; } closedir($dh); } return $files; } $str=<<<EOF これは、ひとつオプションをとるコマンドラインのPHPスクリプトです。 使用法:$argv[0] <option> <option>はファイルを探す起点にしたいディレクトリです。 EOF; $count=0; if(in_array($argv[1],array('--help','-help','-h','-?',''))){ echo "¥n".$str."¥n¥n"; }else{ foreach(recursive_list_files($argv[1]) as $item){ echo $item."¥n"; $count++; } } echo "¥nファイル数:".$count."¥n";
| プログラミング |
2009.06.08 Monday
PHP:テキスト処理>PCRE | 14:16 |
自分が関数を実際に触り、まとめて見るためのメモ
テキスト処理>PCRE
int preg_match(string $pattern,string $subject[,array &$matches[,int $flags[,int $offset]]])
$patternで指定した正規表現を使って$subjectを検索し、見つかった個数を返す。但し0か1。
int preg_match_all(string $pattern,string $subjcet,array &$matches[,int $flag[,int $offset]])
$subjectを検索し、$patternにマッチしたすべての文字列を$matchesに多次元配列を返す(0の場合もある)
mixed preg_replace(mixed $pattern,mixed $replacement,mixed $subject[,int $limit[,int &$count]])
$patternを用いて$subject内を検索し、$replacementに置換する
返り値 - $subjectが配列の場合は配列を、その他の場合は文字列
array preg_split(string $pattern,string $subject[,int $limit=-1[,$int $flags=0]])
$patternにマッチした境界で分割した$subjectの部分もじれ鵜の配列を返す
eregシリーズもあるがpregシリーズの方が速い
テキスト処理>POSIX Regex
int ereg(string $pattern,string $string[,array &$regs)
$patternで指定した正規表現により、大文字小文字を区別して$stringを検索する
$pattern-大文字小文字を区別する正規表現
$string-入力文字列
$regs-$regs[0]は$patternにマッチした文字列全体。$regs[1]は$patternの最初の左括弧が始まる部分文字列を保持、$regs[2]は2番目の左括弧(ry
返り値-$stringの中で$patternがマッチした場合はマッチした文字列の長さを返し、マッチしなかった場合とエラーの場合はFALSEを返す。$regsが渡されていなかったりマッチした文字列の長さが0の場合は1を返す。
int eregi(string $pattern,string $string[,&$regs])
大文字小文字を区別しないereg()
$pattern-大文字小文字を区別しない正規表現
$string-入力文字列
$regs-$regs[0]は$patternのマッチした文字列全体。$regs[1]は$patternの最初の左括弧が始まる部分文字列を保持、$regs[2]は2番目の左括弧(ry
テキスト処理>PCRE
- preg_filter ― Perform a regular expression search and replace
- preg_grep ― パターンにマッチする配列の要素を返す
- preg_last_error ― 直近の PCRE 正規表現処理のエラーコードを返す
- preg_match_all ― 繰り返し正規表現検索を行う
- preg_match ― 正規表現によるマッチングを行う
- preg_quote ― 正規表現文字をクオートする
- preg_replace_callback ― 正規表現検索を行い、コールバック関数を使用して置換を行う
- preg_replace ― 正規表現検索および置換を行う
- preg_split ― 正規表現で文字列を分割する
int preg_match(string $pattern,string $subject[,array &$matches[,int $flags[,int $offset]]])
$patternで指定した正規表現を使って$subjectを検索し、見つかった個数を返す。但し0か1。
//カレントディレクトリの01 - aaa.mp3とかをすべて01aaa.mp3とかにする
foreach(glob("*.mp3") as $item){
if(preg_match("/^([0-9][0-9]) ¥- (.*¥.mp3)$/",$item,$matches))
rename($item,$matches[1]."-".$matches[2]);
}
int preg_match_all(string $pattern,string $subjcet,array &$matches[,int $flag[,int $offset]])
$subjectを検索し、$patternにマッチしたすべての文字列を$matchesに多次元配列を返す(0の場合もある)
$html="bold textclick me";
preg_match_all("/(<([¥w+])[^>]*>)(.*)(<¥/¥¥2>)/",$html,$matches,PREG_SET_ORDER);
foreach($matches as $item){
echo "matched:".$item[0]."¥n";//matched: bold text/matched: (ry
echo "part1:".$item[1]."¥n";//part1:/part1:
echo "part2:".$item[3]."¥n";//part2:bold text/part2:click me
echo "part3:".$item[4]."¥n";//part3:/par3:
}
mixed preg_replace(mixed $pattern,mixed $replacement,mixed $subject[,int $limit[,int &$count]])
$patternを用いて$subject内を検索し、$replacementに置換する
返り値 - $subjectが配列の場合は配列を、その他の場合は文字列
$str="The quick brown fox jumped over the lazy dog";
$pattenrs=array('/quick/','/brown/','/fox/');
$replacements=array('slow','black','bear');
echo preg_replace($patterns,$replacements,$str);
array preg_split(string $pattern,string $subject[,int $limit=-1[,$int $flags=0]])
$patternにマッチした境界で分割した$subjectの部分もじれ鵜の配列を返す
//空白文字で区切る
$str="hypertext preproceccer";
$keywords=preg_split("/[¥s]+/",$str);
//1文字ずつ抜き出す
$str="abcdefg";
$chars=preg_split("//",$str,-1,PREG_SPLIT_NO_EMPTY);
print_r($char);
eregシリーズもあるがpregシリーズの方が速い
テキスト処理>POSIX Regex
int ereg(string $pattern,string $string[,array &$regs)
$patternで指定した正規表現により、大文字小文字を区別して$stringを検索する
$pattern-大文字小文字を区別する正規表現
$string-入力文字列
$regs-$regs[0]は$patternにマッチした文字列全体。$regs[1]は$patternの最初の左括弧が始まる部分文字列を保持、$regs[2]は2番目の左括弧(ry
返り値-$stringの中で$patternがマッチした場合はマッチした文字列の長さを返し、マッチしなかった場合とエラーの場合はFALSEを返す。$regsが渡されていなかったりマッチした文字列の長さが0の場合は1を返す。
//emailの妥当性確認
function validateMail($mail){
if($mail!==""){
if(ereg("^[-A-Za-z0-9_]+[-A-Za-z0-9_¥.]*[@]{1}[-A-Za-z0-9_]+[-A-Za-z0-9_¥.]*[.]{1}[A-Za-z]{2,5}$",$mail)
return true;
else
return false;
}else
return false;
}
int eregi(string $pattern,string $string[,&$regs])
大文字小文字を区別しないereg()
$pattern-大文字小文字を区別しない正規表現
$string-入力文字列
$regs-$regs[0]は$patternのマッチした文字列全体。$regs[1]は$patternの最初の左括弧が始まる部分文字列を保持、$regs[2]は2番目の左括弧(ry
//ビジターがbotかどうかを調べる
function is_bot(){
$bots=split(",","google,yahoo,msn");
//上の配列から(google)|(yahoo)|(msn)を作る
$regex="(".join(")|(",$bots).")";
//上で作った正規表現を使って調べる
return eregi($regex,$_SERVER["HTTP_USER_AGENT"]);
}
| プログラミング |
2009.05.30 Saturday
Perl2周目してて、忘れていたこと 3 | 18:40 |
ラベルはこう使う
do{}文はこう使う
untilとwhileは修飾子で
繰り返し分ではなくdo{}文なので
last,next,redoは使えない
配列からパターンにあった要素のリストを作る
結果:Sun Sat
my @file=('one.txt','two.txt','three.txt');
OUTER:foreach(@file){
open(FILE,$_) or die "$!";
while(<FILE>){
last OUTER if($_ eq 'EXIT');
last if($_ eg 'END');
print $_;
}
close(FILE);
}
do{}文はこう使う
untilとwhileは修飾子で
繰り返し分ではなくdo{}文なので
last,next,redoは使えない
my $line;
do{
$line=<STDIN>;
print $line;
}until($line eq 'END');
do{
$line=<STDIN>;
print $line;
}while($line ne 'END');
配列からパターンにあった要素のリストを作る
my @found=grep(/^S/,@week);
print "@found¥n";
結果:Sun Sat
| プログラミング |
2009.05.27 Wednesday
Perl2周目してて、忘れていたこと 5 | 22:02 |
$text=<<"EOF";
From: itimannnennto@gmail.com
To: nisennnenn@gmail.com
Subuject: maekara@gmail.com
aisiteru-@yahoo.com
EOF
このような$textから、次のようなリストを得たい
(
'itimannnennto@gmail.com',
'nisennnenn@gmail.com',
'maekara@gmail.com',
'aisiteru-@yahoo.com',
)
1つの方法は
my @mail=();
while($text=~/[¥w.-]+@[¥w.-]+/g){
push(@mail,$_);
}
もう1つは
my @mail=($text=~/[¥w.-]+@[¥w.-]+/g);
重複要素の削除の仕方
my %count;
foreach(@words){
$count{$_}++;
}
my @array=sort keys %count;
tr///の慣用的使い方
my $str='This is Ken.';
my $count=($str=~tr/A-Z/A-Z/);
print $count;
結果:2
my $name="Shellingford";
(my $uname=$name)==tr/a-z/-A-Z/;
print "¥$name=$name¥n¥$uname=$uname";
結果:$name=Shellingford
$uname=SHELLINGFORD
grepはリストの中から正規表現で指定したのにマッチする要素をリストで返す
my @lines=("This is Perl¥n",
"Isnt that Perl?¥n",
"You must run Perl¥n",
"Perl is easy to learn¥n");
print grep(/Perl/,@lines);
sub &check{
unless(wantarray){
print "無効コンテキスト";
}elsif(wantarray){
print "リストコンテキスト";
}else{
print "スカラーコンテキスト";
}
}
my $str=`perl print_hello.pl`;
でprint_hello.plの実行結果が$strに入る
From: itimannnennto@gmail.com
To: nisennnenn@gmail.com
Subuject: maekara@gmail.com
aisiteru-@yahoo.com
EOF
このような$textから、次のようなリストを得たい
(
'itimannnennto@gmail.com',
'nisennnenn@gmail.com',
'maekara@gmail.com',
'aisiteru-@yahoo.com',
)
1つの方法は
my @mail=();
while($text=~/[¥w.-]+@[¥w.-]+/g){
push(@mail,$_);
}
もう1つは
my @mail=($text=~/[¥w.-]+@[¥w.-]+/g);
重複要素の削除の仕方
my %count;
foreach(@words){
$count{$_}++;
}
my @array=sort keys %count;
tr///の慣用的使い方
my $str='This is Ken.';
my $count=($str=~tr/A-Z/A-Z/);
print $count;
結果:2
my $name="Shellingford";
(my $uname=$name)==tr/a-z/-A-Z/;
print "¥$name=$name¥n¥$uname=$uname";
結果:$name=Shellingford
$uname=SHELLINGFORD
grepはリストの中から正規表現で指定したのにマッチする要素をリストで返す
my @lines=("This is Perl¥n",
"Isnt that Perl?¥n",
"You must run Perl¥n",
"Perl is easy to learn¥n");
print grep(/Perl/,@lines);
sub &check{
unless(wantarray){
print "無効コンテキスト";
}elsif(wantarray){
print "リストコンテキスト";
}else{
print "スカラーコンテキスト";
}
}
my $str=`perl print_hello.pl`;
でprint_hello.plの実行結果が$strに入る
| プログラミング |
2009.05.25 Monday
Javascriptからphpを実行 | 22:01 |
PHP:JS(JavaScript)からPHPを呼び出しHTML上に出力する方法
こんなこともできるのかと読んでましたが
ならないんですね〜
と思って、単純に「Shellingford」だけをechoする
phpを指定すると...
なりおった!
つまり、サーバーや設定に問題はない
となるとスクリプトか
いったいどこで...
a few hours ago
できた
リアルタイムでちゃんと更新してます
なるほど、ブログパーツはこうやってるくるのか
こんなこともできるのかと読んでましたが
ならないんですね〜
と思って、単純に「Shellingford」だけをechoする
phpを指定すると...
なりおった!
つまり、サーバーや設定に問題はない
となるとスクリプトか
いったいどこで...
a few hours ago
できた
リアルタイムでちゃんと更新してます
なるほど、ブログパーツはこうやってるくるのか
| プログラミング |
2009.05.21 Thursday
Perl2周目してて、忘れていたこと 2 | 21:19 |
以下の文をspliceを使って書くと
ハッシュはこうして全部取り出す
foreach(sort keys %hash){
print "$_ -> $hash{$_}";
}
<=>をスペースシップ演算子と言う
$a<=>$bの時
$a<$bなら-1
$a==$bなら0
$a>$bなら1
-1なら$aが前にくる
1なら$bが前にくる
例えば、
$a==2
$b==4のとき
2<=>4となり
$a<$bなので-1を返す
-1なら$aが前にくる
大量にキーと値を取り出す場合
while(my ($a,$b)=each(%hash))
で取り出した方がメモリにやさしい
そのキーに対する値が存在するかは
if(exists($hash{$key}))
- push(@array,$item)
- $item=pop(@array)
- $item=shift(@array)
- unshift(@array,$item)
- $array[$index]=$item
- splice(@array,@array,0,$item)
- $item=splice(@array,-1)
- $item=splice(@array,0,1)
- splice(@array,0,0,$item)
- splice(@array,$index,0,$item)
ハッシュはこうして全部取り出す
foreach(sort keys %hash){
print "$_ -> $hash{$_}";
}
<=>をスペースシップ演算子と言う
$a<=>$bの時
$a<$bなら-1
$a==$bなら0
$a>$bなら1
-1なら$aが前にくる
1なら$bが前にくる
例えば、
$a==2
$b==4のとき
2<=>4となり
$a<$bなので-1を返す
-1なら$aが前にくる
大量にキーと値を取り出す場合
while(my ($a,$b)=each(%hash))
で取り出した方がメモリにやさしい
そのキーに対する値が存在するかは
if(exists($hash{$key}))
| プログラミング |
| 1/2 | >>
Show some apps list:
Follow on your feed reader:
About this blog:
Linux Mint-centric chronicle with anime girls since 2009.Best View with Google Chrome 1980x1080 dimension.Info 更新は不定期です。
- Mint 18.3 : オススメ Python IDE 8 選
- Mint 18.3 : Python ではじめるコマンドラインツールの作成とパッケージ化
- Linux ユーザーなら Git を活用しよう
- Shell :シェルスクリプトを組もう! Zenity 編
- Shell :シェルスクリプトを組もう! Dialog 編