Microsoft Store からインストールした WSL のための Cmder 設定
Cmder
デフォルトのWSLはタブ機能がなく,また,フォント等の見栄えがよくない. Cmder はそれらを補うためのターミナルエミュレータである. 自分はWSL以外にCmderを使うつもりはないが,PowerShellやコマンドプロンプトもエミュレートできる.
Cmder の設定で若干詰まったので,メモ
WSL を Microsoft Store からインストールした場合,Cmder のターミナルセットに Store からインストールした WSL が表示されない.
このため,自分で追加する必要がある.
このセットアップをするに当たって,以下のサイトを参考にした.
具体的なプリセットの追加方法
- Setting を開く
- Startup の Tasks を開く
+
で Predefined tasks を追加- 左上の枠(Default task for new console の上) にプリセットの名前を入力
- 右下の大き目の枠に以下を入力
%windir%\System32\wsl.exe {xxxxxxxxxxx} ~ -cur_console:p
上記の{xxxxxxxxxxx}
は後で編集する. Win + r
で"ファイル名を指定して実行"を開くregedit
を入力し,レジストリエディター開くHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Lxss
を開き,{xxxxxx}
の形式のフォルダをクリックする.(この形式のフォルダは複数ある場合がある.)DistributionName
の項目を確認することで,どのフォルダが Store からインストールした WSL のものか何となくわかる.Legacy
と書いてあったら Store からではないもの.Ubuntu-18.04
とか書いてたらきっと Store からインストールしたもの.- Cmder の Setting に戻る.
- フォルダ名をコピーし,CmderのSettingの
{xxxxxxxxxxx}
の部分を書き換える. Up
ボタン連打して追加したプリセットを一番上に上げたり,Default task for new console にチェック入れたりする.- StartUp から General に移り,"Choose your startup task or even a shell with arguments"の設定を変更し,追加したプリセットをデフォルトにする.
- Save Setting
ドットファイルの install/uninstall スクリプトの作成
クラウドを利用したドットファイルの共有
複数の環境(パソコン)間でドットファイルを共有するために,クラウドを利用すると便利である.
このため,最近,ドットファイルの管理にクラウドを導入した.
また,クラウド環境として自分はGitHubを採用した.
ドットファイルの install スクリプトの作成
インストールの手間を短縮
新しい環境を使い始める際や既存の環境をリセットした際の, ドットファイルをインストールする手間を短縮したい. このため,今回はインストールスクリプトを作成する.
インストールスクリプトの設計方針
GitHubで知り合いのリポジトリを漁っていると,以下のコードが釣れた.
#!/bin/bash for f in .??* do [[ "$f" == ".git" ]] && continue [[ "$f" == ".DS_Store" ]] && continue ln -s $HOME/dotfiles/$f $HOME/$f done
上記コードはホームディレクトリにドットファイルのリンクを貼るスクリプトである.このコードを拡張し,インストールスクリプトを作成することにした.
達成したい課題
- MacとWSL(Windows)で実行可能
現状,MacとWSLのターミナルを使っているので, どちらからでも実行できるようにする. - MacとWSLでインストールするドットファイルを変更
ターミナルが異なる場合,共有したいドットファイルもあれば,共有したくない(異なる環境設定にしたい)ものもある. このため,異なるターミナル,今回はMacとWSLでインストールするドットファイルを変更する. - リンクが貼れない状況に対応
貼りたいドットファイルと同名のファイルが既にホームディレクトリに存在する場合,$ ln
コマンドにエラーを出力させず,自分が設定した文字列を出力する(エラー処理).
各課題への対処
MacとWSL(Windows)で実行可能
Macで実行できたコードがWSLで動かない,といったことは何度もあったが,正直,原因がよくわからなかった. 色々試した結果,以下の3点を行うことでうまく動いた.
function
を使わない.
WSLの方でエラーを吐かれた.このため,function
を使わず,代わりに別ファイルを作成し,そのファイル(スクリプト)を呼び出すことにした.- bashではなく,shで実行する.
shebangをbashからshに変えるだけでなく,以下の様に実行コマンドもsh
を使う.
$ sh ./install.sh
- 条件式に
[[
を使わず,全て[
を使う.
[[
はbashのコマンドらしいので,[
に変更する.
MacとWSLでインストールするドットファイルを変更
以下の方法で対処する.
以下のコードで実行OS(ターミナル)を判断し,ホームディレクトリに共有ドットファイルと専用ドットファイルのリンクを貼る.
#!/bin/sh # OS(ターミナル)の種類を判断 if [ "$(uname)" = 'Darwin' ]; then OS='Mac' elif [ $(echo $(uname -r) | grep -e 'Microsoft') ]; then OS='WSL' else echo "Your platform ($(uname -a)) is not supported." OS='undefined' fi echo $OS' terminal\n' # 各OS(ターミナル)に応じて dotfile のリンクを貼る. if [ ! $OS = "undefined" ]; then sh scripts/link_dotfiles_to_home.sh $OS"/" fi # 各OS(ターミナル)共通の dotfile のリンクを貼る. sh scripts/link_dotfiles_to_home.sh ""
また,link_dotfiles_to_home.sh
は指定したディレクトリ下のドットファイルのリンクをホームディレクトリに貼るスクリプトである.
第一引数でそのディレクトリを指定する.
これは参考コードのfor f in .??*
をfor f in $1.??*
に改変することで実現した.
リンクが貼れない状況に対応
以下の状況を条件文により分岐し,処理.
- 既にファイルがある場合
[NG] を出力 - 既にリンクがある場合
[skip] を出力 - それ以外(リンクが貼れる場合)
リンクを貼り,[OK] を出力
また,各[NG], [skip] および [OK] のecho
出力には色を付けた.
link_dotfiles_to_home.sh
のソースコードは以下の通り.
#!/bin/sh for f in $1.??* do # ファイルの絶対パスを取得 dotfile_path=$HOME"/dotfiles/"$f # ファイルパスの一番右の"/"以降の文字列を取得 dotfile_name=${dotfile_path##*/} # 特定のファイルは pass [ "$dotfile_name" = ".git" ] && continue [ "$dotfile_name" = ".gitignore" ] && continue [ "$dotfile_name" = ".DS_Store" ] && continue # ファイルのリンクが既に貼られていれば skip を出力 if [ -h $HOME"/"$dotfile_name ]; then echo "[\033[36mskip\033[0m] "$dotfile_name # ファイルの実体(!=リンク)があれば,NG を出力 elif [ -e $HOME"/"$dotfile_name ]; then echo "[\033[31mNG\033[0m] "$dotfile_name # ファイルのリンクが貼られていなければ,シンボリックリンクを貼る. else ln -s $dotfile_path $HOME"/"$dotfile_name echo "[\033[32mOK\033[0m] "$dotfile_name fi done
install スクリプトの実行による出力は以下の通り.
uninstall スクリプトの作成
処理内容はほぼ install スクリプトと同じで,作成されたリンクをアンリンクするだけ.
具体的に,link_dotfiles_to_home.sh
のソースの一部を以下のコードに改変し,delete_symbolic_links.sh
として保存する.
uninstall.sh
はinstall.sh
のlink_dotfiles_to_home.sh
を呼ぶコードをdelete_symbolic_links.sh
を呼ぶコードに変えるだけ.
#!/bin/sh for f in $1.??* do # ファイルの絶対パスを取得 dotfile_path=$HOME/dotfiles/$f # ファイルパスの一番右の"/"以降の文字列を取得 dotfile_name=${dotfile_path##*/} # 特定のファイルは pass [ "$dotfile_name" = ".git" ] && continue [ "$dotfile_name" = ".gitignore" ] && continue [ "$dotfile_name" = ".DS_Store" ] && continue # ファイルのリンクが既に貼られていれば,ホームディレクトリのリンクを削除 if [ -h $HOME"/"$dotfile_name ]; then unlink $HOME"/"$dotfile_name echo "[\033[32mOK\033[0m] "$dotfile_name # ファイルの実体(!=リンク)があれば,NG を出力 elif [ -e $HOME"/"$dotfile_name ]; then echo "[\033[31mNG\033[0m] "$dotfile_name # ファイルのリンクが貼られていなければ skip else echo "[\033[36mskip\033[0m] "$dotfile_name fi done
CSVファイルの編集(データ整形)の効率化
Excelを使ったデータ整形から卒業したい
現状,手軽なCSVデータの整形方法は以下の2パターン
上記方法でも短時間で柔軟なデータ整形が可能ではあるが, せっかく大学や趣味でプログラミングの勉強をしているので, python等のスクリプトコードを利用してデータ整形したい.
しかし,データを整形する度にプログラムを一から作ることは面倒である. また,アルゴリズムを考え,細かい文法を思い出す(調べる)必要がある場合もある. これらの対処として,今回は以下を行う.
データ整形用コードのテンプレート
今回は「特定の列について,元の値に応じた編集」を行うためのpythonスクリプトを作成する. 例えば,以下のような編集を想定する.
- ある列の内容を,各値に応じて「大」「中」「小」といったカテゴリに書き換える.
- 単純に,特定の列の各値(セル)の先頭に特定の文字列を追加する.
上記を考慮したデータ整形用コード(python3)は以下の通り.
import pandas as pd imput_file = 'input.csv' output_file = 'output.csv' csv = pd.read_csv(imput_file) header = csv.columns colnum = len(header) output_text = "{0}\n".format(', '.join(header)) for index, row in csv.iterrows(): # row['列名']の値を編集することで,ファイルを編集できます. output_row = [row['大会名'], row['1位'], row['2位'], row['3位']] output_row_str = map(str, output_row) output_row = ', '.join(output_row_str) # 改行込みで変数に格納 output_text += output_row + '\n' # 編集した内容をファイルに出力 f = open(output_file, 'w') f.write(output_text) f.close()
上記コードの中で,row['列名']
変数の値を書き換えることで,出力ファイルの内容が変わる.
対象データに応じてテンプレートの内容を変更
テンプレートコードの以下の2行について,
imput_file = 'input.csv' output_row = [row['大会名'], row['1位'], row['2位'], row['3位']]
この2行を対象データに応じて変更する.
具体的に,input_file
変数には文字列は対象データのファイル名を代入し,
output_row
変数に代入する配列は対象データのヘッダー名に対応する.
これを,以下の手順により実現する.
- テンプレートコードの上記2行を適当な文字列に書き換えたファイル(
editCSV.template.py
)を用意 - 別のpythonコード(
genEditCSV.py
)で対象データを読み込む - 対象データのファイル名とヘッダー名に応じたデータ整形用コード(
editCSV.py
)を出力
editCSV.template.py
について
editCSV.py
との差分は(+/-)で示す.
import pandas as pd - imput_file = 'input.csv' + imput_file = # {{input_file}} output_file = 'output.csv' csv = pd.read_csv(imput_file) header = csv.columns colnum = len(header) output_text = "{0}\n".format(', '.join(header)) for index, row in csv.iterrows(): # row['列名']の値を編集することで,ファイルを編集できます. - output_row = [row['大会名'], row['1位'], row['2位'], row['3位']] + output_row = # {{output_row}} output_row_str = map(str, output_row) output_row = ', '.join(output_row_str) # 改行込みで変数に格納 output_text += output_row + '\n' # 編集した内容をファイルに出力 f = open(output_file, 'w') f.write(output_text) f.close()
genEditCSV.py
について
import csv import sys import os args = sys.argv # 引数のCSVファイル名について,validation if len(args) < 2: print('CSVファイルを引数で指定してください.') sys.exit(1) if not os.path.isfile(args[1]): print('CSVファイル {0} がありません.'.format(input_file)) sys.exit(1) input_file = args[1] output_file = 'editCSV.py' this_path = '{0}/scripts/editCSV'.format(os.environ['HOME']) f = open(input_file, 'r') reader = csv.reader(f) header = next(reader) colnum = len(header) # editCSV.py に出力するコードを作成 output_code = '' for i in range(colnum): output_code += "row['{0}'], ".format(header[i]) f.close() output_code = "output_row = [{0}]".format(output_code[:-2]) # editCSV.template.py の '# {{output}}' の部分に output_code を置換 f_template = open('{0}/editCSV.template.py'.format(this_path), 'r') f_output = open(output_file, 'w') for row in f_template: # '# {{input_file}}' の行を探し,置換 if row.find('# {{input_file}}'): row = row.replace('# {{input_file}}', "'{0}'".format(input_file)) # '# {{output_row}}' の行を探し,置換 if row.find('# {{output_row}}'): row = row.replace('# {{output_row}}', output_code) f_output.write(row) f_output.close() f_template.close()
任意のディレクトリにeditCSV.py
を出力
自分の環境ではホームディレクトリ直下にscripts
ディレクトリを配置しており,
このディレクトリ下に以下のファイルを配置した.
- scripts/
- editCSV/
- editCSV.template.py
- genEditCSV.py
- editCSV/
このgenEditCSV.py
を任意のディレクトリから呼び出せるように,以下の様なalias
を貼った.
$ alias editCSV='python3 ~/scripts/editCSV/genEditCSV.py'
ここまでで,今回の開発は終了.
未対応の課題について
- 特定の項目名が空であるデータや,そもそもヘッダーがないデータへの対応
- 列の追加・削除
- windowsで実行した場合,pandasの処理により数値が少数(10 -> 10.0)に変換される.