Visual Studio Codeでキーボードショートカットが効かなくなった時に確認すること

Visual Studio Codeでいつも使えていたキーボードショートカットが使えなくなったり、新たにキーボードショートカットを使おうとして期待していた動きと違う場合に、どこを確認して、どう対処すればいいかを解説します。

どういったことが起きている可能性が高いのか

まず、キーボードショートカットが効かなかったり、期待した動きをしていない場合、どういったことが起きているかについて説明します。

このような事象が起きている原因には、大きく3つの可能性が考えられます。

  • コマンドに割り当てられていたキーボードショートカットが削除されている
  • キーボードショートカットが別のコマンドに割り当てられている
  • キーボードショートカットが他のキーボードショートカットの一部となっている

次に私が遭遇した具体的な事例をもとに手順を確認していきます。

キーボードショートカットの設定を確認する

まずはキーボードショートカットの設定を確認しましょう。

キーボードショートカットの設定を表示するには、Ctrl+K Ctrl+S(macOSはCommand+K Command+S)を入力します。

キーボードショートカットを確認する

やり方はいくつかありますが、まずはキーボードショートカットが設定されているのかを確認します。

上部にあるテキストボックスの右側にあるキーボードのマークをクリックすると、キーボードショートカットで検索することができるようになります。

テキストボックスでキーボードショートカットを入力すると、対象のキーボードショートカットが割り当てられているコマンドに絞り込まれます。

ここでは、行全体を選択するキーボードショートカットのCtrl+L(macOSではCommand+L)が効かなかったので、調べています。

見たところ、キーボードショートカットは自体は正しく設定されているようです。

キーボードショートカットを修正する

調べた結果を元に、具体的に修正を行なっていきます。

コマンドが見つからなかった場合

キーボードショートカットを入力しても期待していたコマンドがヒットしなかったときは、何らかの理由でキーボードショートカットが解除されたか、別のコマンドに割り当てられています。

その場合は、再度 キーボードショートカットを割り当ててください。

コマンドが見つかった場合

コマンドが見つかった場合、当該キーボードショートカットを一部に持つ別のコマンドが割り当てられてる可能性が高いです。

これを確認するために、キーボードショートカットを再度して、ステータスバーを確認してみてください。他のキーボードショートカットの一部になっている場合は以下のように2番目のキーを待つ表示が現れます。

該当のコマンドが何かもわかりませんし、2番目のキーがわからないとキーボードショートカットでも探せないため、地道ですが目視で探してください。

本例では拡張機能「Live Server」のキーボードショートカットの一部にCtrl+L(macOSの場合はCommand+L)が使われており、これによって本来実行したかった行全体を選択が使用できなくなっていました。

問題を解決するには他のショートカットキーに変更するかキーボードショートカットを削除してください。

対象のキーボードショートカットを右クリックし、変更したい場合は「キー バインドを変更する…」を選択、削除したい場合は「キー バインドを削除」を選択します。
今回は特に使っていないキーボードショートカットだったので、削除することにしました。

動作確認をする

修正が完了したら動作確認をしてみましょう。

問題なくキーボードショートカットが機能していれば問題解決です。

[macOS] iTerm2で自動的にログを取得する設定を行う

セッション開始時に自動的にログを取得する方法について解説します。

ログの出力先を用意する

作成先はどこでも構いません。使用量にもよりますが、長期間運用しているとそれなりのサイズとなるため、空き容量が少ないストレージや容量が圧迫したときに動作に影響のあるストレージは避けた方がよいでしょう。

特に、容量の少ないMacBookを使用している場合は、すぐにディスクがいっぱいになる場合がありますので、外部の大容量ストレージを使うか、ログを定期的に削除するなどの対策をご検討ください。

本記事では、Google Drive for desktopで作成されるGoogle Driveにログを出力するディレクトリを作成しています。

iTerm2のプロファイル(Profile)を開く

iTerm2のメニューからProfiles > Open Profiles...Command+O)でProfilesダイアログを開きます。

Profilesダイアログ

利用状況にもよりますが、星マークがついているProfile Nameが現在使用しているプロファイル(設定)になります。多くの型はDefaultに星マークがついていると思いますが、私の環境ではGuakeを使用しているため、Guakeプロファイルに星マークがついています。

星マークがついている行を選択し、Edit Profiles...を選択してください。

Preferencesダイアログ

ProfilesタブのSessionタブに移動し、Miscellaneousの「Automatically log session input to files in:」にチェックをつけ、ログの保存先のディレクトリのパスをテキストボックスに入力します。

セッション開始時にログを自動的に作成する設定

変更は保存操作をしなくても即時反映されるため、作業はこれで完了ですので、そのまま閉じてください。

ログが出力されることを確認する

では、実際にセッションを新規作成してログファイルが作成されることを確認してみましょう。

iTerm2のメニューからShell > New WindowCommand+N)もしくはShell > New TabCommand+T)で新しいセッションを開始します。
セッション開始後、Finderでログの出力先にファイルが作成されたことを確認します。

特にファイル名は指定していませんが、ファイル名にセッションを開始した年月日時分秒が含まれていますので、後で探すときに困ることはなさそうです。

では、ファイルを開いてみましょう。ここではテキストエディット.appでファイルを開いています。

ログファイル

Shellの設定によりますが、私の環境ではzshellを使用し、Powerlevel10Kを導入しているため、非常に見にくくなっています。この時点で読める表示になっている方は以降の手順は必須ではありませんが、そうでない方は以降で説明する設定を行ってみてください。

ログをプレーンテキストで出力する

先ほどの設定に戻り、「Log plain text」にチェックをつけます。

Preferencesダイアログ

これで、再度セッションを開始してログを出力した後で、ログファイルをテキストエディット.appで開いてみます。

ログファイル

多少文字化けしている箇所はありますが、先ほどに比べると圧倒的に読みやすくなっています。

「Log plain text」チェックボックスのON、OFFを両方試していただいて環境にあった方を選択してください。

Pandasで日付項目を日付型として扱う

Pandasで日付項目をdatetime[ns]型に変換し、日付型として扱う方法について解説します。

日付項目を読み込む

次のCSVファイルを特にオプションを指定せずに読み込みます。

date1        ,date2      ,date3     ,date4   ,date5     ,date6   ,date7
2020年12月31日,2020年6月9日,2020-12-31,2020-6-9,2020/12/31,2020/6/9,20201231

このファイルには4種類(うち3種類は0埋めありとなしの2パターン用意)の日付項目が設定されています。

import pandas as pd
df = pd.read_csv('test.csv')

各項目がどの型で読み込まれているかinfo関数で確認します。

df.info()

yyyymmdd形式はint64型、それ以外はobject型(str型)で読み込まれているのがわかります。

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1 entries, 0 to 0
Data columns (total 7 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   date1   1 non-null      object
 1   date2   1 non-null      object
 2   date3   1 non-null      object
 3   date4   1 non-null      object
 4   date5   1 non-null      object
 5   date6   1 non-null      object
 6   date7   1 non-null      int64 
dtypes: int64(1), object(6)
memory usage: 184.0+ bytes

日付型に変換する

日付項目を加工したり、年・月・日などを取り出しやすくするために、datetime64[ns]型に変換しておくと便利です。

datetime64[ns]型に変換するには、pandas.to_datetime関数を使います。

df['datetime1'] = pd.to_datetime(df['date1'], format="%Y年%m月%d日")
df['datetime2'] = pd.to_datetime(df['date2'], format="%Y年%m月%d日")
df['datetime3'] = pd.to_datetime(df['date3'])
df['datetime4'] = pd.to_datetime(df['date4'])
df['datetime5'] = pd.to_datetime(df['date5'])
df['datetime6'] = pd.to_datetime(df['date6'])
df['datetime7'] = pd.to_datetime(df['date7'], format="%Y%m%d")

年月日形式の項目はformatオプションを指定しないとエラーになります。また、yyyymmdd形式はエラーにはなりませんが、値をナノ秒と見なして読み込むため、1970-01-01 00:00:00.020201231のような値になってしまいます。こちらもformatオプションの指定が必要です。

読み込み時に 日付型に変換する

読み込んでみてから、「あ、これ日付項目か」と気づく場合は前述の方法を使っていただければよいですが、事前にどれが日付項目かわかっている時は読み込む時に日付型として読み込む方が効率的です。

標準の日付パーサーで変換できる場合

yyyy-mm-dd形式やyyyy/mm/dd形式、yyyymmdd形式の場合は標準の日付パーサーで変換できます。

次のような形式の CSVファイルの場合、

date    ,average
2021/8/1,28.7
2021/8/2,28.6
2021/8/3,29.0
2021/8/4,29.5
2021/8/5,29.1
2021/8/6,29.1
2021/8/7,27.9

以下のようにすることで、項目dateを日付datetime64[ns]型で読み込むことができます。

df = pd.read_csv('weather.csv', 
                 dtype={"date": str},
                 parse_dates=["date"])
df.info()

直接dtypedatetime64を指定するのではなく、一旦dtypeオプションではstr型を指定して、parse_datesオプションで日付型にしたい項目を指定して変換するというやり方になります。

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 2 columns):
 #   Column    Non-Null Count  Dtype         
---  ------    --------------  -----         
 0   date      7 non-null      datetime64[ns]
 1    average  7 non-null      float64       
dtypes: datetime64[ns](1), float64(1)
memory usage: 240.0 bytes

日付パーサーを自作して変換する場合

年月日形式などPandasが用意している標準の日付パーサーで変換できない場合は日付パーサーを自作して指定することで日付変換ができるようになります。

次のようなCSVファイルの場合、

date,       average
2021年8月1日,28.7
2021年8月2日,28.6
2021年8月3日,29.0
2021年8月4日,29.5
2021年8月5日,29.1
2021年8月6日,29.1
2021年8月7日,27.9

先ほどと同じコードで読み込むと、エラーは発生しませんが、datetime64[ns]型には変換されません。

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 2 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   date      7 non-null      object 
 1    average  7 non-null      float64
dtypes: float64(1), object(1)
memory usage: 240.0+ bytes

このような場合は、日付パーサーを自作し、date_parserオプションで指定します。

from datetime import datetime
my_parser = lambda date: datetime.strptime(date, '%Y年%m月%d日')
df = pd.read_csv('weather.csv', 
                 dtype={"date": str},
                 parse_dates=["date"],
                 date_parser=my_parser)
df.info()

先ほどとは異なり、datetime64[ns]型に変換されていることが確認できます。

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 2 columns):
 #   Column    Non-Null Count  Dtype         
---  ------    --------------  -----         
 0   date      7 non-null      datetime64[ns]
 1    average  7 non-null      float64       
dtypes: datetime64[ns](1), float64(1)
memory usage: 240.0 bytes

pandas.datetime.strptimeを使用するサンプルを見かけると思いますが、pandas.datetimeは将来的に削除される予定ですので、今後はdatetimeを使用しましょう。
/var/folders/3r/qfsmvnsd5sz0qvf367p_d5j00000gp/T/ipykernel_83309/1860031930.py:1: FutureWarning: The pandas.datetime class is deprecated and will be removed from pandas in a future version. Import from datetime module instead.
my_parser = lambda date: pd.datetime.strptime(date, ‘%Y年%m月%d日’)

質的変数と量的変数

統計学で扱うデータ(変数)は、質的変数と量的変数に分類できます。

質的変数(qualitative variable)

質的変数とは、データをいくつかに分類したもの(それぞれをカテゴリといいます)の中から1つのカテゴリを取るような変数です。質的変数の具体例には、性別(男、女)、血液型(A型、B型、AB型、O型)、学校の成績(A、B、C、D、E、F)、病気の進行段階(ステージ0、ステージⅠ、ステージⅡ、ステージⅢ、ステージⅣ)などがあります。
質的変数は、名義尺度と順序尺度に分けることができます。

名義尺度(nominal scale)

質的変数のうち、カテゴリ間に順序性がないものを名義尺度といいます。名義尺度の具体例には性別、血液型などがあります。

順序尺度(ordinal scale)

質的変数のうち、カテゴリ間に順序性があるものを順序尺度といいます。名義尺度に加え、順序にも意味がある尺度ともいうことができます。順序尺度の具体例には学校の成績や病気の進行段階などがあります。

量的変数(quantitative variable)

量的変数とは、数値で与えられる変数です。量的変数の具体例には、摂氏温度、身長、体重、世帯人数、西暦などがあります。

間隔尺度(interval scale)

量的変数のうち、各値の間隔に意味があるものを間隔尺度といいます。順序尺度に加え、値の間隔にも意味がある尺度ともいうことができます。間隔尺度の具体例には摂氏温度、世帯人数、西暦などがあります。

比例尺度(ratio scale)

量的変数のうち、ある値が他の値と比較して何倍あるかに意味があるものを比較尺度といいます。間隔尺度に加えて、比にも意味がある尺度ということができます。比例尺度の具体例には身長や体重などがあります。

どちらに分類されるかは変わることがある

ある変数が質的変数か量的変数かということについては、ある程度の傾向はあるものの、絶対にこちらだということはありません。

例えば、日付はある日を表すラベルと見なせば質的変数(順序尺度)として扱うこともできますが、日付の差に着目する場合は量的変数(間隔尺度)として扱うこともあります。テストの点数でも、0点から100点までの量的変数(比例尺度)として捉えることもできますが、0点〜10点、11点〜20点・・・のように度数で扱うなら質的変数(順序尺度)として捉えることもできます。

このように、どのように収集するのか、どう集計するのか、どのように扱うのか、どこに注目するのか、などによって同じ変数であっても分類が変わることがあることに注意が必要です。過去に質的変数で扱っていたとしても、今回はどのように扱うかきちんと精査することが大切です。

kubectlコマンドでリモートクラスタに接続する

リモートサーバーに構築したkubernatesにローカルからアクセスできるようにします。

認証情報を出力する

本例ではmicrok8sでKubernetesクラスターを構築しています。

まずは、リモートサーバーにSSH等で接続し、認証情報を取得します。

$ microk8s kubectl config view --raw

上記コマンドで出力すると、以下のような内容が出力されます(一部、内容を変更しています)。

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data:xxxxxx
    server: https://127.0.0.1:16443
  name: microk8s-cluster
contexts:
- context:
    cluster: microk8s-cluster
    user: admin
  name: microk8s
current-context: microk8s
kind: Config
apiVersion: v1
clusters:
- cluster:
    server: https://192.168.0.16:16443
  name: microk8s-cluster
contexts:
- context:
    cluster: microk8s-cluster
    user: admin
  name: microk8s
current-context: microk8s
kind: Config
preferences: {}
users:
- name: admin
  user:
    password: xxxxx
    username: admin
apiVersion: v1
apiVersion: v1
apiVersion: v1
preferences: {}
users:
- name: admin
  user:
    token: xxxxx

ローカルに認証情報を設定する

前述の出力内容のうち、以下の部分が127.0.0.1になっているため、IPアドレスをリモートアドレスに書き換えます。

- cluster:
    certificate-authority-data:xxxxxx
    server: https://127.0.0.1:16443
  name: microk8s-cluster

server欄をリモートアドレスに書き換えます。

- cluster:
    certificate-authority-data:xxxxxx
    server: https://192.168.0.16:16443
  name: microk8s-cluster

これを~/.kube/configに設定します。

ファイル自体がない場合はそのまま設定してもらってよいのですが、すでに設定がある場合は必要な部分だけを追記してください。

PandasでCSVファイル読み込む(read_csv関数)

PandasでCSVファイルを読み込む方法について解説します。
本記事では読み込みオプションの解説ではなく、CSVファイルや CSVファイルに似たファイルの読み込み方について解説しています。

CSVファイルを読み込む

次のCSVファイルを読み込んでデータフレームを作成します。

社員番号,氏名,姓,名,生年月日,役職
001,山田 太郎,山田,太郎,1990-01-01,係長
002,田中 花子,田中,花子,1990-12-31,部長

ふつうのCSVファイルであればオプションなしで読み込むことができます。

import pandas as pd
test1_df = pd.read_csv('test1.csv')

カンマやダブルクォーテーションをカラムに含むCSVファイルを読み込む

カラムにカンマを含む場合、ダブルクォーテーションでカラムを囲みます(a,b"a,b") 。もちろん、カンマを含んでいない場合でもダブルクォーテーションでカラムを囲んでもかまいません。
ダブルクォーテーションでカラムを囲んでいるときにカラムにダブルクォーテーションが含まれる場合はエスケープする必要があります。エスケープする場合はダブルクォーテーションを二つ重ねます(a"b"a""b")。

次のCSVファイルを読み込んでデータフレームを作成します。

社員番号,氏名,姓,名,生年月日,役職
001,"山田,""太郎",山田,太郎,1990-01-01,係長
002,"田中,""花子",田中,花子,1990-12-31,部長

Pandasのread_csv関数は基本的なCSVの仕様に対応しているため、特にオプションを使用せずに読み込むことができます。

import pandas as pd
test2_df = pd.read_csv('test2.csv')

タブ区切りファイルを読み込む

最近は見かけることが減りましたが、タブ区切りファイル(TSVファイル)をread_csv関数で読み込むことができます。

次のTSVファイルを読み込んでデータフレームを作成します。

社員番号	氏名	姓	名	生年月日	役職
001	山田 太郎	山田	太郎	1990-01-01	係長
002	田中 花子	田中	花子	1990-12-31	部長

オプションなしで読み込むことはできないため、sepで区切り文字を指定します。

import pandas as pd
test3_df = pd.read_csv('test3.csv', sep='\t')

任意の区切り文字のファイルを読み込む

出力する側の問題でダブルクォーテーションによる区切り文字が使用できない場合や出力または中間での加工の都合で、カラム内に絶対に含まれない文字を使ってファイルを出力することがあります。
先ほどのタブ区切りの応用でread_csv関数を使って読み込むことができます。

垂直バー(|)を区切り文字にした次のCSVファイルを読み込んでデータフレームを作成します。

社員番号|氏名|姓|名|生年月日|役職
001|山田 太郎|山田|太郎|1990-01-01|係長
002|田中 花子|田中|花子|1990-12-31|部長

TSVファイルのときと同様に、sepで区切り文字を指定します。

import pandas as pd
test4_df = pd.read_csv('test4.csv', sep='|')

まとめ

read_csv関数を使うことで、CSVファイルやTSVファイルだけでなく、任意の区切り文字のファイルも読み込むことができます。

運用上の理由からCSVファイルでは都合が悪いケースもありますので、その場合は任意の区切り文字を使うことを検討してみてはいかがでしょうか。

GruntでSASS/SCSSをビルドする

GruntでSASS/SCSSをビルドする方法について解説します。

パッケージのインストール

まずはNodeプロジェクトを作成します。

$ npm init -y

必要なパッケージをインストールしていきます。

$ npm install -D grunt grunt-sass node-sass grunt-postcss autoprefixer@^9 grunt-contrib-watch load-grunt-tasks

インストールするパッケージは以下のとおりです。実際に使用したバージョンも併記しておきます。

  • grunt 1.5.3
  • grunt-sass 3.1.0
  • node-sass 7.0.1
  • grunt-postcss 0.9.0
  • autoprefixer 9.8.8
  • grunt-contrib-watch 1.1.0
  • load-grunt-tasks 5.1.0

また、Node.jsのバージョンは16.14.2、npmのバージョンは8.10.0を使用しています。

執筆時点(2022/05/17)では、autoprefixerはバージョン指定なしでインストールするとv10系がインストールされます。
grunt-postcss v0.9系と組み合わせると、
Warning: [object Object] is not a PostCSS plugin Use --force to continue.
という警告が発生して実行に失敗(Aborted)します。そのため、バージョン指定なしで上記エラーが発生する場合は、npm install -D autoprefixer@^9のようにv9系を指定してインストールしてください。

grunt-sass

GruntでSASS/SCSSをビルドするパッケージにはgrunt-sassgrunt-contrib-sassがありますが、grunt-contrib-sassの方はRubyのsassを使用しています。
実際にインストールするとわかりますが、インストール時に以下のメッセージが出力され、Rubyのsassは非推奨に なっていることがわかります。

Ruby Sass has reached end-of-life and should no longer be used.

このため、grunt-contrib-sassではなく、node-sassが使用できるgrunt-sassを使用しています。

grunt-postcss、autoprefixer

ベンダープリフィックスを自動で付与するために使用します。

grunt-contrib-watch

SASS/SCSSを開発環境でビルドするときは都度コマンドを打ってビルドするのではなく、自動でビルドする方が楽だと思いますので、変更監視用のgrunt-contrib-watchを使用します。

load-grunt-tasks

インストールしたgrunt-*パッケージを使用するためには、Gruntfile.js内

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-sass');

のようにロードする必要があります。少ないうちは特に問題になりませんが、ロードするパッケージが多くなると管理が煩雑になるため、以下のように書くだけでロードできるload-grunt-tasksを使用しています。

  require("load-grunt-tasks")(grunt);

SASS/SCSSをビルドする

ではGruntfile.jsを作成していきます。

本例では、以下のような構造のプロジェクトになっており、sass/main.scssをビルドしてdist/css/main.cssとして出力するGruntfile.jsを作成しています。

.
├── dist/
│   └── css/
│       └── main.css
├── sass/
│   └── main.scss
├── Gruntfile.js
├── node_modules/
├── package-lock.json
└── package.json

動作確認のために用意したsass/main.scssは以下のようになっています。

.button {
  border: 1px;
  background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%);
  &:hover {
    border: 2px;
  }
}

これをビルドするGruntfile.jsは以下のとおりです。

const sass = require("node-sass");

module.exports = function (grunt) {
  grunt.initConfig({
    // Sassタスク
    sass: {
      options: {
        implementation: sass,
        style: "expanded",
      },
      dist: {
        files: {
          "dist/css/main.css": "sass/main.scss",
        },
      },
    },
  });

  require("load-grunt-tasks")(grunt);

  grunt.registerTask("build", ["sass"]);
};

sassタスク

sassタスクでは実装(implementation)にnode-sassを指定しています。その他のオプションは自由ですが、ビルドされたCSSファイルを確認したかったので、style: "expanded"を指定しています。

タスクの定義(build)

本例では、buildタスクを定義しています。

package.jsonbuildタスクを実行するスクリプトを作成し、

{
  ・・・
  "scripts": {
    "build": "grunt build",
    ・・・
  },
}

実行してみましょう。

$ npm run build

> example@1.0.0 build
> grunt build

Running "sass:dist" (sass) task

Done.

エラーなく実行され、dist/css/main.cssに以下の内容が出力されました。

.button {
  border: 1px;
  background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%); }
  .button:hover {
    border: 2px; }

Autoprefixerを使用する

次にベンダープリフィックスが自動付与されるようにGruntfile.jsを修正します。

const sass = require("node-sass");
const autoprefixer = require("autoprefixer"); // 追加

module.exports = function (grunt) {
  grunt.initConfig({
    // Sass
    sass: {
      options: {
        implementation: sass,
        style: "expanded",
      },
      dist: {
        files: {
          "dist/css/main.css": "sass/main.scss",
        },
      },
    },
    // <- ここから
    // PostCSS
    postcss: {
      options: {
        processors: [autoprefixer()],
      },
      dist: {
        src: "dist/css/main.css",
      },
    },
    // ここまでを追加 ->
  });

  require("load-grunt-tasks")(grunt);

  grunt.registerTask("build", ["sass", "postcss"]); // <- "postcss"を追加
};

sassタスクで出力されたdist/css/main.cssに対してベンダープリフィックスを付与するようにしています。SASS/SCSSファイルではなくCSSファイルに対して実行する点に注意してください。

次にAutoprefixerがCSSにどのベンダープリフィックスをつけるかなど決めるために使用する.browserslistrcを作成します。

last 1 versions
ie >= 11

設定値自体はベンダープリフィックスがつくのを確認するために設定しているものですので、推奨設定とかそういうものではありません。

こちらも同様に実行してみます。

$ npm run build

> example@1.0.0 build
> grunt build

Running "sass:dist" (sass) task

Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.

Done.

sassタスクの後にpostcssタスクが実行されていることがわかります。

出力されたdist/css/main.cssを見てみると、linear-gradientにベンダープリフィックスがついた行が出力されていることがわかります。

.button {
  border: 1px;
  background-image: -webkit-linear-gradient(top, #8bcc8e 0%, #a7f5ab 100%);
  background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%); }
  .button:hover {
    border: 2px; }

Autoprefixerを書き方について注意事項

Autoprefixerの使用方法を調べると以下のような書き方をしているサイトもあります。

    postcss: {
      options: {
        processors: [
          autoprefixer({
            browsers: ["last 1 versions", "ie >= 11"],
          }),
        ],
      },
      dist: {
        src: "dist/css/prime.css",
      },
    },

本記事の執筆時点(2022/05/17)では、この書き方をして実行してみると以下のようなメッセージが出力されます。

$ npm run build

> primecss@1.0.0 build
> grunt build


  Replace Autoprefixer browsers option to Browserslist config.
  Use browserslist key in package.json or .browserslistrc file.

  Using browsers option can cause errors. Browserslist config 
  can be used for Babel, Autoprefixer, postcss-normalize and other tools.

  If you really need to use option, rename it to overrideBrowserslist.

  Learn more at:
  https://github.com/browserslist/browserslist#readme
  


Running "sass:dist" (sass) task

Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.

Done.

この例では正しく動作しているものの、説明では、

  • browsersオプションではなくpackage.jsonまたは.browserslistrcを使用すること
  • browsersオプションを使うとエラーが発生することがある
  • どうしても使いたい場合はoverrideBrowserslistオプションを使用すること

となっています。毎回赤い文字でメッセージが表示されるのも困りますので、本記事では.browserslistrcを使用しています。

SASS/SCSSファイルを監視する

最後にファイルの変更を監視するように変更し、都度ビルドコマンドを実行しなくても済むようにしましょう。

const sass = require("node-sass");
const autoprefixer = require("autoprefixer");

module.exports = function (grunt) {
  grunt.initConfig({
    // <- ここから
    // Watch
    watch: {
      target: {
        files: ["sass/**/*"],
        tasks: ["sass", "postcss"],
      },
    },
    // ここまでを追加 ->
    // Sass
    sass: {
      options: {
        implementation: sass,
        style: "expanded",
      },
      dist: {
        files: {
          "dist/css/main.css": "sass/main.scss",
        },
      },
    },
    // PostCSS
    postcss: {
      options: {
        processors: [autoprefixer()],
      },
      dist: {
        src: "dist/css/main.css",
      },
    },
  });

  require("load-grunt-tasks")(grunt);

  grunt.registerTask("build", ["sass", "postcss"]);
  grunt.registerTask("build:watch", ["sass", "postcss", "watch"]); // <- build:watchタスクを追加
};

タスクの実行時に一度SASS/SCSSをビルドし、以降は変更されるたびにSASS/SCSSをビルドしたいので、["sass", "postcss", "watch"]のように指定しています。
最初の"sass", "postcss"がないと、何かしら変更を加えないと初回のビルドが行われないのでご注意ください。

本記事では、監視を行うタスクはwatchタスクとし、実行するために定義するタスクをbuild:watchタスクとしています。仮に、
grunt.registerTask("watch", ["sass", "postcss", "watch"]);
のようにしてしまうと、["sass", "postcss", "watch"]"watch"が自分自身を呼び出してしますため、無限ループに陥ってしまいます。
initConfigで定義しているタスクもregisterTaskで定義しているタスクも同じタスクですので、タスク名の重複にはご注意ください。

package.jsonwatchスクリプトを追加し、作成したbuild:watchタスクを呼び出すように修正します。

 {
  ・・・
  "scripts": {
    "build": "grunt build",
    "watch": "grunt build:watch",
    ・・・
  },
}

では、実行してみます。

$ npm run watch

> primecss@1.0.0 watch
> grunt build:watch

Running "sass:dist" (sass) task

Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.

Running "watch" task
Waiting...

実行後、sassタスク、postcssタスクの順に実行し、最後にwatchタスクを実行して監視状態になったことがわかります。

では、監視しているsass/main.scssを更新してみましょう。使用しているエディタによって異なりますが、ファイル自体変更しなくても保存するだけでタイムスタンプが変わるので、変更を検知してくれます。

>> File "sass/main.scss" changed.

Running "sass:dist" (sass) task

Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.

Running "watch" task
Completed in 0.017s at Sat May 21 2022 23:27:13 GMT+0900 (日本標準時) - Waiting...

監視対象の指定について

sass/main.scssをビルド対象としているため、sass/**/*を監視対象としています。sass/*ではなくsass/**/*を監視対象としているのは、今後サブディレクトリを作成した場合でも、きちんと変更が検知されるようにするためです。

Poetryを使ってDjangoプロジェクトを作成する

Poetryを使ってDjangoのプロジェクトを作成する方法について解説します。

前提条件

本手順では、現在使用しているPythonの環境にdjangoをインストールしない方法でプロジェクトを作成しています。
公式の手順とは若干手順が異なることに注意してください。

空のプロジェクトを作成する

まずは空のプロジェクトを作成します。
poetry newコマンドで自動で作成されるプロジェクトの構造とDjangoのプロジェクト構造は相性が悪いので、ここでは普通にmkdirコマンドで空のプロジェクトを作成して、プロジェクト内に移動します。

$ mkdir demoapp
$ cd demoapp

ここではdemoappというプロジェクトを作成していますが、実際に作成するときは作成したいプロジェクトの名前で作成してください。

Poetryの初期化を行う

Poetryの初期化を行います。

ここでは必要最低限の設定にしていますが、必要に応じて設定を変更してください。

$ poetry init

This command will guide you through creating your pyproject.toml config.

Package name [demoapp]:  
Version [0.1.0]:  
Description []:  
Author [Taro Yamada <taro.yamada@example.com>, n to skip]:  
License []:  
Compatible Python versions [^3.10]:  

Would you like to define your main dependencies interactively? (yes/no) [yes] no
Would you like to define your development dependencies interactively? (yes/no) [yes] no
Generated file

[tool.poetry]
name = "demoapp"
version = "0.1.0"
description = ""
authors = ["Taro Yamada <taro.yamada@example.com>"]

[tool.poetry.dependencies]
python = "^3.10"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"


Do you confirm generation? (yes/no) [yes] yes

この時点ではDjangoをインストールせず初期化のみ行っています。
これは単にコマンドの方が楽だからという理由だけですので、poetry initコマンド実行時にdjangoをインストールしてもかまいません。

Djangoをインストールする

poetry initをした際に対話的にdjangoをインストールした場合はこの手順を飛ばしてください。

poetry addコマンドでdjangoをインストールします。
執筆時点では4.0.4がインストールされました。

$ poetry add django

インストールするときは-Dオプションをつけずにインストールします。

Djangoプロジェクトを作成する

Djangoプロジェクトを作成します。
以下のdjango-admin startprojectコマンドでDjangoプロジェクトをカレントディレクトリに作成します。プロジェクト名は最初に作成したディレクトリ名と同じ名前(本手順ではdemoapp)を指定します。

$ poetry run django-admin startproject demoapp .

コマンドを実行するときにdjango-adminではなくdjango-admin.pyとすると実行時に例外が発生する場合があります。
私の環境では[Errno 2] No such file or directory: b'/Users/taro/.cargo/bin/django-admin.py'のようなエラーが出力されました(Rustインストール済みの環境です)。

これでDjangoプロジェクトが作成できました。
以降はpoetry run python manage.pyで各種コマンドを実行できるようになります。

グローバルインストールしたAngular CLIをアップデートする

グローバルインストールしたAngular CLIをアップデートする手順について解説します。

注意事項

本手順はグローバルインストールされたAngular CLIのバージョンアップする手順です。
プロジェクトのAngularをバージョンアップする手順ではないのでご注意ください。

アップデート前の状態

アップデート前の状態を確認しておきます。ng versionでインストールされているAngular CLIのバージョンを確認することができます。

$ ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 13.3.1
Node: 16.14.2
Package Manager: npm 8.7.0
OS: darwin arm64

Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1303.1 (cli-only)
@angular-devkit/core         13.3.1 (cli-only)
@angular-devkit/schematics   13.3.1 (cli-only)
@schematics/angular          13.3.1 (cli-only)

本手順では、13.3.1がアップデート前の状態になります。

Angular CLIをアップデートする

Angular CLIを13.3.1から13.3.4にアップデートしましょう。

まずは、現在インストールしているAngular CLIをアンインストールします。

$ npm uninstall -g @angular/cli

removed 196 packages, and audited 1 package in 567ms

found 0 vulnerabilities

次にAngular CLIを再度インストールします。ここでは最新版をインストールしていますが、特定のバージョンにアップデートしたい場合は@angular/cli@x.x.xのようにバージョンを指定してください。

$ npm install -g @angular/cli

added 196 packages, and audited 197 packages in 10s

24 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

インストール後に再度バージョンを確認します。

$ ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 13.3.4
Node: 16.14.2
Package Manager: npm 8.8.0
OS: darwin arm64

Angular:
...

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1303.4 (cli-only)
@angular-devkit/core         13.3.4 (cli-only)
@angular-devkit/schematics   13.3.4 (cli-only)
@schematics/angular          13.3.4 (cli-only)

Angular CLIのバージョンが13.3.4にアップデートされたことを確認できました。

この手順はバージョンアップにもバージョンダウンにも使用できます。

SSH接続時に「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」のエラーが出るときの対処法

今までSSH接続していたサーバを再インストールしたり、IPやホスト名は同じですが別のサーバが導入した場合にSSH接続しようとすると、「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」というエラー(警告)が出て接続できない場合があります。

$ ssh 192.168.0.16
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:FNjxRHnzRjm709c/sch7pZ9SuPjj0S6lp8ZrY+0scks.
Please contact your system administrator.
Add correct host key in /Users/t0k0sh1/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/t0k0sh1/.ssh/known_hosts:6
Host key for 192.168.0.16 has changed and you have requested strict checking.
Host key verification failed.

過去に接続していたサーバーを再インストールしたため、リモートホスト鍵が変わっており中間者攻撃(Man In The Middle Attack)を疑われています。

known_hostsからホスト鍵を削除する

もちろん、悪意のあるサーバーに接続していないことが確認されていることが前提となりますが、known_hostsから以前登録していたホスト鍵を削除することでこの問題を解消できます。

$ ssh-keygen -R 192.168.0.16
# Host 192.168.0.16 found: line 4
# Host 192.168.0.16 found: line 5
# Host 192.168.0.16 found: line 6
/Users/t0k0sh1/.ssh/known_hosts updated.
Original contents retained as /Users/t0k0sh1/.ssh/known_hosts.old

ssh-keygen -Rコマンドで接続先のサーバーを指定するとknown_hostsからホスト鍵を削除できます。

再度接続を試みと、初回接続時と同じように接続するかの確認が行われます。

$ ssh 192.168.0.16
The authenticity of host '192.168.0.16 (192.168.0.16)' can't be established.
ED25519 key fingerprint is SHA256:FNjxRHnzRjm709c/sch7pZ9SuPjj0S6lp8ZrY+0scks.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.0.16' (ED25519) to the list of known hosts.
t0k0sh1@192.168.0.16's password:
Welcome to Ubuntu 22.04 LTS (GNU/Linux 5.15.0-27-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue Apr 26 11:20:18 PM UTC 2022

  System load:  0.080078125       Temperature:             39.0 C
  Usage of /:   6.7% of 97.87GB   Processes:               143
  Memory usage: 1%                Users logged in:         1
  Swap usage:   0%                IPv4 address for wlp1s0: 192.168.0.16


1 update can be applied immediately.
To see these additional updates run: apt list --upgradable


Last login: Tue Apr 26 23:03:25 2022
t0k0sh1@192.168.0.16:~$

依然と同じホスト鍵を使用している場合はこの問題は起きませんが、そうでない場合は、

  • サーバーを再インストールした
  • 別のサーバーだが同じIPアドレスやホスト名のサーバを立てた
  • ホスト鍵を変更した

といったときに発生します。

ISOファイルをUSBフラッシュドライブ(USBメモリ)に書き込む(macOS編)

以前、WindowsでRufusを使って、ISOファイルをUSBフラッシュドライブ(以下、USBメモリ)に書き込む方法をご紹介しました。

今回はmacOSでISOファイルをUSBメモリに書き込む方法を解説します。

USBメモリのディスクデバイスを確認

diskutil listコマンドを使って、マウントしているUSBメモリが割り当てられているディスクデバイスを確認します。

$ diskutil list
/dev/disk0 (internal):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                         1.0 TB     disk0
   1:             Apple_APFS_ISC                         524.3 MB   disk0s1
   2:                 Apple_APFS Container disk3         994.7 GB   disk0s2
   3:        Apple_APFS_Recovery                         5.4 GB     disk0s3

/dev/disk3 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +994.7 GB   disk3
                                 Physical Store disk0s2
   1:                APFS Volume Macintosh HD            15.2 GB    disk3s1
   2:              APFS Snapshot com.apple.os.update-... 15.2 GB    disk3s1s1
   3:                APFS Volume Preboot                 350.0 MB   disk3s2
   4:                APFS Volume Recovery                804.6 MB   disk3s3
   5:                APFS Volume Data                    107.5 GB   disk3s5
   6:                APFS Volume VM                      20.5 KB    disk3s6

/dev/disk4 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *7.9 GB     disk4
   1:             Windows_FAT_32 UBUNTU-SERV             7.9 GB     disk4s1

上記の場合、/dev/disk4が今回ISOファイルを書き込むUSBフラッシュドライブ(USBメモリ)です。すでに過去に書き込み済みのUSBメモリであれば名前(NAME)、そうでない場合は容量(SIZE)等で判断してください。

USBメモリを初期化する

ディスクデバイスが誤っていないかを十分に確認のうえ、diskutil eraseDiskコマンドでUSBメモリを初期化します。

$ diskutil eraseDisk FAT32 UBUNTU2204 /dev/disk4
Started erase on disk4
Unmounting disk
Creating the partition map
Waiting for partitions to activate
Formatting disk4s2 as MS-DOS (FAT32) with name UBUNTU2204
512 bytes per physical sector
/dev/rdisk4s2: 15023424 sectors in 1877928 FAT32 clusters (4096 bytes/cluster)
bps=512 spc=8 res=32 nft=2 mid=0xf8 spt=32 hds=255 hid=411648 drv=0x80 bsec=15052800 bspf=14672 rdcl=2 infs=1 bkbs=6
Mounting disk
Finished erase on disk4

今回使用しているUSBメモリは8GBなので、FAT32でフォーマットしています。
名前(NAME)を指定したので、その名前に変わっているか確認してみましょう。

$ diskutil list
/dev/disk0 (internal):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                         1.0 TB     disk0
   1:             Apple_APFS_ISC                         524.3 MB   disk0s1
   2:                 Apple_APFS Container disk3         994.7 GB   disk0s2
   3:        Apple_APFS_Recovery                         5.4 GB     disk0s3

/dev/disk3 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +994.7 GB   disk3
                                 Physical Store disk0s2
   1:                APFS Volume Macintosh HD            15.2 GB    disk3s1
   2:              APFS Snapshot com.apple.os.update-... 15.2 GB    disk3s1s1
   3:                APFS Volume Preboot                 350.0 MB   disk3s2
   4:                APFS Volume Recovery                804.6 MB   disk3s3
   5:                APFS Volume Data                    107.5 GB   disk3s5
   6:                APFS Volume VM                      20.5 KB    disk3s6

/dev/disk4 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *7.9 GB     disk4
   1:                        EFI EFI                     209.7 MB   disk4s1
   2:       Microsoft Basic Data UBUNTU2204              7.7 GB     disk4s2

タイプ(TYPE)および名前(NAME)が変わっていることからUSBメモリが初期化されたことが確認できます。

マウントを解除する

書き込みを行う前にマウントを解除しておきます。これをしておかないと、ISOファイルを書き込む時にエラーになります。

$ diskutil umountDisk /dev/disk4
Unmount of all volumes on disk4 was successful

デスクトップからUSBメモリのアイコンが消えたかを確認してください。消えていればマウントが解除されています。

ISOファイルをUSBメモリにコピーする

では、ISOファイルをUSBメモリにコピーしていきましょう。USBメモリへの書き込みにはddコマンドを使用します。

書き込みの際にはディスクデバイスが正しいことを十分確認のうえ行ってください。
また、ddコマンド実行時にsudoコマンドを併用する場合、カレントディレクトリを表す”~“を使用すると正しいパスにならない場合がありますので、フルパスで指定したり、ISOファイルのあるディレクトリに移動してから実行してください。
ddコマンドのデフォルトブロックサイズが512なので、本例では、1M(1MB)に増やして実行しています。

$ sudo dd if=/Users/t0k0sh1/Downloads/ubuntu-22.04-live-server-amd64.iso of=/dev/disk4 bs=1M
1398+1 records in
1398+1 records out
1466714112 bytes transferred in 148.687247 secs (9864424 bytes/sec)

最後に

以上で、USBメモリへの書き込みが完了しました。実際に使用して正しく書き込めていることを確認してください。

本手順ではディスクデバイスの指定を間違わないようにすることが最も重要になります。この点には十分注意して操作を実施してください。

モバイルバージョンを終了