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メモリへの書き込みが完了しました。実際に使用して正しく書き込めていることを確認してください。

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

UbuntuでノートPCを閉じてもサスペンドさせない方法

ノートPCの蓋を閉じたときにサスペンドさせないようにする設定について解説します。

本手順はUbuntu Server 20.04で確認しています

実施する作業は以下の2点です。

  • ノートPCの蓋を閉じてもサスペンドしないようにする
  • 一定期間操作していないときにサスペンドしないようにする

ノートPCの蓋を閉じてもサスペンドしないようにする

最初に行う設定は、ノートPCを閉じたときにサスペンドしないようにする設定です。

/etc/systemd/logind.confを編集します。

$ sudo vi /etc/systemd/logind.conf

/etc/systemd/logind.confの以下の行を探し、

#HandleLidSwitch=suspend

以下のように書き換えてください。

HandleLidSwitch=ignore

もし、該当行がない場合は追記してください。

書き替えたあとはsystemdを再起動します。

$ sudo systemctl restart systemd-logind.service

一定期間操作していないときにサスペンドしないようにする

前述の設定だけでは不十分で、しばらくキーボードやマウスの操作をしていないときはサスペンドしてしまいます。

環境依存だと思いますが、インストールしたばかりのUbuntu Serverには/usr/share/gdmが存在しませんでしたので、先にディレクトリを作成します。

$ sudo mkdir -p /usr/share/gdm/dconf

ディレクトリ作成後にファイルを作成します。

$ sudo vi /usr/share/gdm/dconf/90-local-settings

ファイルの内容は以下のようにしてください。

[org / gnome / settings-daemon / plugins / power]
sleep-inactive-ac-timeout = 0
sleep-inactive-battery-timeout = 0

ファイルがある場合は上記のように編集してください。

ファイルを保存後、Ubuntuを再起動してください。

$ sudo reboot

RustのOption型を理解する

Option型、Optional型を持つプログラミング言語はいくつもあります。ここでは、RustのOption型の使い方について説明します。

Option型とは

Option型は、値が存在する場合と存在しない場合を表現できる列挙型です。標準ライブラリでは、以下のように定義されています。

pub enum Option<T> {
    None,
    Some(T),
}

なぜOption型を使用するのか

Rustでは、nullundefinedのような値が存在しないため、値の有無を示すためにOption型が使用されます。これにより、コンパイル時に値の有無を考慮しなければならないことが明示され、ヌルポインタ例外のようなランタイムエラーを防ぐことができます。

Option型の使い方

具体的な使用例で、使用方法を確認していきましょう。

Option型を定義する

Option型を定義する場合は、型をOption<T>型にし、値はSomeまたはNoneを使います。

    // Option<i32>型の変数を定義する
    // 値が存在する場合はSomeに値を渡して代入する
    let val: Option<i32> = Some(100);
    //  値が存在しない場合はNoneを代入する
    let none: Option<i32> = None;

値が存在しているときだけ取り出し、存在しないときはデフォルト値を使う

値が存在するときだけその値を取り出し、値が存在しないときはデフォルト値を使う場合はmatch式を使うとよいでしょう。

// 偶数の時だけ2倍の値を返す
fn get_double_value_when_even(num: i32) -> Option<i32> {
    return if (num % 2) == 0 {
        Some(num * 2)
    } else {
        None
    }
}

fn main() {
    let value = match get_double_value_when_even(10) {
        None => 0,
        Some(v) => v,
    };
    println!("value is {}", value);
}

この例では、値が存在する場合はその値を変数に代入し、存在しない場合はデフォルト値の0を変数に代入しています。

単純に値を取り出したいだけであれば、unwrap_or関数を使うことで、もっと簡単に書くことができます。

// 偶数の時だけ2倍の値を返す
fn get_double_value_when_even(num: i32) -> Option<i32> {
    return if (num % 2) == 0 {
        Some(num * 2)
    } else {
        None
    }
}

fn main() {
    let value = get_double_value_when_even(10).unwrap_or(0);
    println!("value is {}", value);
}

値が存在しているか存在しないかで処理を分岐する

値が存在する時はその値を使って処理を行い、値が存在しなときはそれとは別の処理を行う場合はif文を使うとよいでしょう。

// 偶数の時だけ2倍の値を返す
fn get_double_value_when_even(num: i32) -> Option<i32> {
    return if (num % 2) == 0 {
        Some(num * 2)
    } else {
        None
    }
}

fn main() {
    if let Some(value) = get_double_value_when_even(10) {
        println!("result: {}", value);
    } else {
        println!("値は存在しません");
    }
}

この例では、値が存在するときはその値を表示し、値が存在しないときは存在しない旨のメッセージを表示しています。

値が存在している/していないを判定する

値自体が必要なわけではなく、値が存在している/していないだけが必要な状況ということがあります。このような場合はis_some関数やis_none関数を使用するとよいでしょう。

struct Person {
    pub name: String,
    pub age: u32,
}

impl Person {
    /// Personテーブルをidで検索する
    fn findById(id: &str) -> Option<Person> {
        if id == "user01" {
            Some(Person {
                name: String::from("John"),
                age: 20,
            })
        } else {
            None
        }
    }
}

fn main() {
    if Person::findById("user01").is_some() {
        // ID"user01"のPersonが存在する場合
        println!("Personは存在します");
    }
}

この例では、値が存在するかどうかをis_some関数で判定しています。値が存在しない場合を判定したい場合はis_none関数を使います。

まとめ

RustのOption型は、コードの安全性と明確さを向上させるための強力なツールです。値が存在するかどうかを常に考慮することで、予期しないエラーのリスクを減少させます。

Node.jsで開発環境をセットアップする(ESLint、Prettier、husky)

Node.jsの開発環境で、以下の機能をセットアップする方法について解説します。

  • ESLintによるlint
  • Prettierによるコードフォーマット
  • huskyによるpre-commit git hooks

開発環境を作成する

最初に構築対象となる開発環境を用意します。

$ npm init -y
Wrote to /Users/t0k0sh1/workspace/node_lint/package.json:

{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

今回の説明とは関係ないため、デフォルトのままで進めます。

パッケージをインストールする

次に必要なパッケージをインストールします。

  • eslint – lintツール
  • prettier – formatterツール
  • eslint-config-prettier – eslintのフォーマットがprettierと競合する場合はeslint側をOFFにする
  • husky – pre-commit git hooksツール
$ npm i -D eslint eslint-config-prettier prettier husky

added 85 packages, and audited 86 packages in 4s

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

found 0 vulnerabilities

eslint-plugin-prettierは非推奨になっているため、eslint-config-prettierを使用しています。

インストール後のpackage.jsonは以下のようになっています。

// package.json
{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.13.0",
    "eslint-config-prettier": "^8.5.0",
    "husky": "^7.0.4",
    "prettier": "^2.6.2"
  }
}

lintの設定を行う

まずはESLintの設定を行います。ここでは必要最低限の設定にしています。prettiereslint:recommendの後に書いてください。

// .eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "prettier"
  ]
}

次にeslintでのlint(修正あり)とprettierでのフォーマットを行うスクリプトを追加します。

// package.json
{
  "name": "node_lint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint --cache --fix . && prettier --write ."
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.13.0",
    "eslint-config-prettier": "^8.5.0",
    "husky": "^7.0.4",
    "prettier": "^2.6.2"
  }
}

コードを作成して動作確認を行う

実際のコードを作成して動作確認をしておきましょう。

// index.js
function hello(name) {
  return 'Hello, ' + name;
}

console.log(hello("John"));

簡単なプログラムを書きました。動作確認ができるようにlintでエラーになるコードになっています。

では動作確認します。

$ node index.js
Hello, John

エラーにならず動作していることを確認できました。

では、このコードに対してlintprettierを実行します。

$ npm run lint

> node_lint@1.0.0 lint
> eslint --cache --fix . && prettier --write .


/Users/t0k0sh1/workspace/node_lint/index.js
  6:1  error  'console' is not defined  no-undef

✖ 1 problem (1 error, 0 warnings)

consoleが未定義であるとエラーになりました。これは後で修正(除去)しますが、今はこのままにしておきます。

ここまでに作成したコードをコミットしておきます。

git initコマンドでgitリポジトリを初期化します。

$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint:   git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint:   git branch -m <name>
Initialized empty Git repository in /Users/t0k0sh1/workspace/node_lint/.git/

コミットするにあたり、node_modules.eslintcacheは対象から外したいので、.gitignoreを作成しておきます。

// .gitignore
node_modules/
.eslintcache

作成したファイルをステージングエリアに追加します。

$ git add .

ローカルリポジトリにコミットしておきます。

$ git commit -m 'first commit'
[master (root-commit) ec47452] first commit
 5 files changed, 1682 insertions(+)
 create mode 100644 .eslintrc.json
 create mode 100644 .gitignore
 create mode 100644 index.js
 create mode 100644 package-lock.json
 create mode 100644 package.json

pre-commit git hooksを設定する

huskyを使ってpre-commit git hooksを設定していきます。手順は公式の手順(https://github.com/typicode/husky)に従いますが、pre-commitに追加するコマンドがnpm run lintになっている点にだけ注意してください(公式の手順ではnpm test

$ npm set-script prepare "husky install"
$ npm run prepare

> node_lint@1.0.0 prepare
> husky install

husky - Git hooks installed
$ npx husky add .husky/pre-commit "npm run lint"
husky - created .husky/pre-commit
$ git add .husky/pre-commit

手順どおりに進めると、package.jsonがステージングエリアに追加されていないため、これを追加してローカルリポジトリにコミットします。

$ git add package.json
$ git commit -m 'setup husky'

> node_lint@1.0.0 lint
> prettier --write '**/*.js' && eslint .

index.js 25ms

/Users/t0k0sh1/workspace/node_lint/index.js
  6:1  error  'console' is not defined  no-undef

✖ 1 problem (1 error, 0 warnings)

husky - pre-commit hook exited with code 1 (error)

先ほどコマンド実行で確認した時と同じようにconsoleが未定義であるとエラーになりました。

pre-commitが機能していることを確認できましたが、念のためコミットされていないかを確認しておきます。

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   .husky/pre-commit
        modified:   package.json

コミットが行われておらず、pre-commitが正しく動作していることを確認できました。

コードを修正して再度コミットする

コードを修正して再度コミットしましょう。

ここでは単純にconsole.log関数を削除しておきます。

// index.js
function hello(name) {
  return "Hello, " + name;
}

hello("John");

念のため、コマンドで確認しておきます。

$ npm run lint

> node_lint@1.0.0 lint
> eslint --cache --fix . && prettier --write .

.eslintrc.json 20ms
index.js 7ms
package-lock.json 30ms
package.json 6ms

エラーにならないことを確認できましたので、ステージングエリアに追加します。

$ git add index.js

では、再度コミットしましょう。

$ git commit -m 'setup husky'
> node_lint@1.0.0 lint
> prettier --write '**/*.js' && eslint .

index.js 25ms
[master ed5dcae] setup husky
 3 files changed, 7 insertions(+), 2 deletions(-)
 create mode 100755 .husky/pre-commit

今度はエラーが表示されず、コミットが実行されました。

git statusgit logでもコミットされていることを確認します。

git status
On branch master
nothing to commit, working tree clean
$ git log
commit ed5dcae1e5e2487854e78e0d388a2f503324231d (HEAD -> master)
Author: Takashi Yamashina <takashi.yamashina@gmail.com>
Date:   Sat Apr 9 12:51:04 2022 +0900

    setup husky

commit 15186ea9211ed9d5ee4de9aa7dab7e2e04bac9de
Author: Takashi Yamashina <takashi.yamashina@gmail.com>
Date:   Sat Apr 9 12:37:45 2022 +0900

    first commit

問題なくコミットできていることが確認できました。

Prettierで特定のファイル、フォルダを対象から除外する(.prettierignore)

Prettierで特定のファイルやフォルダを対象から除外する方法について解説します。

.prettierignoreを作成する

.prettierignoreを作成し、そこに対象から除外したいファイルやフォルダを書きます。

config.js
test/

上記の例では、config.jsというファイルと、testフォルダを対象から除外しています。

実際に試してみる

実際にどう動くのか確認しましょう。

package.json

package.jsonは次のとおりです。prettierをインストールし、prettierコマンドを実行するスクリプトを追加しています。

{
  "name": "node_prettier",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "format": "prettier --write '**/*.js'"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "prettier": "^2.6.2"
  }
}

Prettierは設定ファイルがなくても実行可能なため、ここでは設定ファイルは作成せずに進めます。

プロジェクトの構造

プロジェクトの構造は以下のようになっており、用意した4つのJSファイルはすべてフォーマットされる書き方になっています。

$ tree
.
├── file1.js
├── file2.js
├── dir3
│   └── file3.js
├── dir4
│   └── file4.js
├── package-lock.json
└── package.json

各ファイルの中身は若干の違いはありますが、以下のような内容になっています。

function file1() {
console.log('file1');
}

関数内のインデントがない点と、文字列の囲み文字がダブルクォーテーションではなくシングルクォーテーションになっている点がフォーマットの対象となる箇所です。

Prettierを実行する

最初に.prettierignoreを用意せずに実行します。

$ npm run format

> node_prettier@1.0.0 format
> prettier --write '**/*.js'

dir3/file3.js 22ms
dir4/file4.js 2ms
file1.js 2ms
file2.js 1ms

プロジェクト直下の2ファイル、2つのフォルダ内のそれぞれのファイルが対象になっていることがわかります。

function file1() {
  console.log("file1");
}

実際にファイルを見てみると、インデントおよび文字列の囲み文字が修正されていることが確認できました。

次に.prettierignoreを作成し、プロジェクト直下の1ファイルと2つのファイルのうちの1つを除外してから再度実行してみましょう。

file2.js
dir4/

先ほどと同様に実行してみると、除外したファイルとフォルダ内のファイルが表示されなくなりました。

$ npm run format

> node_prettier@1.0.0 format
> prettier --write '**/*.js'

dir3/file3.js 23ms
file1.js 2ms

ファイルも確認してみると、

ファイル名が表示されたファイルは、先ほどと同様にフォーマットされていますが、

function file1() {
  console.log("file1");
}

ファイル名が表示されなかった(除外された)ファイルはフォーマットされていません。

function file2() {
console.log('file2');
}

node_modulesの除外は不要

実行してみるとわかりますが、node_modulesの除外は不要です。

そのため、対象としたいフォルダ内に除外したいファイルやフォルダがない場合は.prettierignoreを作成する必要はありません。

ESLintで特定のファイル、フォルダを対象から除外する(.eslintignore)

ESLintで特定のファイルやフォルダを対象から除外する方法について解説します。

.eslintignoreを作成する

.eslintignoreを作成し、そこに対象から除外したいファイルやフォルダを書きます。

config.js
test/

上記の例では、config.jsというファイルと、testフォルダを対象から除外しています。

実際に試してみる

実際にどう動くのか確認しましょう。

package.json

package.jsonは次のとおりです。eslintをインストールし、eslintコマンドを実行するスクリプトを追加しています。

{
  "name": "node_eslint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint ./"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "eslint": "^8.12.0"
  }
}

.eslintrc.json

.eslintrc.jsonは必要最小限にしています。

{
    "extends": [
      "eslint:recommended"
    ]
}

プロジェクトの構造

プロジェクトの構造は以下のようになっており、用意した4つのJSファイルはすべてLintでエラーが検出されます。

$ tree
.
├── file1.js
├── file2.js
├── dir3
│   └── file3.js
├── dir4
│   └── file4.js
├── .eslintrc.json
├── package-lock.json
└── package.json

ESLintを実行する

最初に.eslintignoreを用意せずに実行してみます。

$ npm run lint                                                                                                                     

> node_eslint@1.0.0 lint
> eslint ./


/Users/t0k0sh1/workspace/node_eslint/dir3/file3.js
  1:10  error  'file3' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/dir4/file4.js
  1:10  error  'file4' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file1.js
  1:10  error  'file1' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file2.js
  1:10  error  'file2' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

✖ 8 problems (8 errors, 0 warnings)

プロジェクト直下の2ファイルもフォルダ内の2ファイルもエラーになっていることがわかります。

次に.eslintignoreを作成し、プロジェクト直下の1ファイルと2つのファイルのうちの1つを除外してから再度実行してみましょう。

file2.js
dir4/

先ほどと同様に実行してみると、除外したファイルとフォルダ内のファイルがエラーに表示されなくなりました。

$ npm run lint

> node_eslint@1.0.0 lint
> eslint ./


/Users/t0k0sh1/workspace/node_eslint/dir3/file3.js
  1:10  error  'file3' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

/Users/t0k0sh1/workspace/node_eslint/file1.js
  1:10  error  'file1' is defined but never used  no-unused-vars
  2:1   error  'console' is not defined           no-undef

✖ 4 problems (4 errors, 0 warnings)

node_modulesの除外は不要

実行してみるとわかりますが、node_modulesの除外は不要です。

そのため、対象としたいフォルダ内に除外したいファイルやフォルダがない場合は.eslintignoreを作成する必要はありません。

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