メインコンテンツまでスキップ

「Linux」タグの記事が19件件あります

全てのタグを見る

Makefile のすすめ

背景と課題意識

日々の業務で Python スクリプトを用いてデータ変換の自動化を行うと、次のような課題に直面することが多い。

  • 元データの一部だけが更新されたのに全体を実行し直して時間を浪費する。
  • どの手順がどのファイルに依存しているかが曖昧で、実行順序や抜け漏れの管理が難しい。
  • スクリプトの変更がどの成果物に影響するか掴みにくい。

Makefile は「依存関係」と「差分だけの再実行(インクリメンタルビルド)」を標準機能として備え、これらの課題を小さな記述で解決できる道具である。

Make の基本

  • ターゲット: 生成物(例: output/report.csv)
  • 依存関係: 生成に必要なファイル(例: data/clean/*.csv やスクリプト)
  • レシピ: 生成に使うコマンド(例: python scripts/aggregate.py ...)

Make は「依存関係がターゲットより新しいときにだけレシピを実行」する。これにより、元データや Python スクリプトを更新した場合に、必要な箇所のみが自動的に再実行される。

最小構成の Makefile 例

以下は raw データをクリーニングし、集計レポートを作る一連の処理を差分実行する例である。

# Makefile
SHELL := bash
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
.ONESHELL:
.DEFAULT_GOAL := all

RAW_DIR := data/raw
CLEAN_DIR := data/clean
OUT_DIR := output

RAW := $(wildcard $(RAW_DIR)/*.csv)
CLEAN := $(patsubst $(RAW_DIR)/%.csv,$(CLEAN_DIR)/%.csv,$(RAW))
REPORT := $(OUT_DIR)/report.csv

# ディレクトリは順序限定依存(存在しなければ作るが、更新判定には使わない)
$(CLEAN_DIR) $(OUT_DIR):
mkdir -p $@

# 集計レポートはクリーン済み CSV と集計スクリプトに依存
$(REPORT): $(CLEAN) scripts/aggregate.py | $(OUT_DIR)
python scripts/aggregate.py -i $(CLEAN_DIR) -o $@

# 各 raw CSV から対応する clean CSV を生成
$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv scripts/clean.py | $(CLEAN_DIR)
python scripts/clean.py -i $< -o $@

.PHONY: all clean status

all: $(REPORT)

clean:
rm -rf $(CLEAN_DIR) $(OUT_DIR)

# 何が再ビルド対象かを確認するヘルパ
status:
@echo "RAW : $(RAW)"
@echo "CLEAN : $(CLEAN)"
@echo "REPORT: $(REPORT)"
@echo
@echo "Dry-run (what would run):"
@$(MAKE) -n all

この構成により次が実現できる。

  • 元データ data/raw/foo.csv を更新すると、対応する data/clean/foo.csv だけが再生成される。
  • scripts/clean.py を更新すると、クリーン工程だけが必要分再実行される。
  • scripts/aggregate.py を更新すると、集計レポートだけが再実行される。

動作イメージ

# 初回(すべて生成)
make -j

# 一部の raw が更新(そのファイルのクリーンとレポートのみ再実行)
touch data/raw/a.csv
make -j

# クリーニングスクリプトが更新(全クリーンとレポートを再実行)
touch scripts/clean.py
make -j

# 集計スクリプトが更新(レポートのみ再実行)
touch scripts/aggregate.py
make

「何が走るか」を事前確認するには make -n が有効である。

スクリプト依存の設計指針

  • 各ルールには、それを直接呼び出す Python スクリプトを依存関係として明示することが重要である。
  • 複数のモジュールに分割している場合、対象ルールが import するモジュールまで依存に含めると変更が正しく伝播する。簡便策としては対象ディレクトリの Python ファイル一式を変数化して依存に加える。

例(簡便策):

PY_SRCS := $(wildcard scripts/**/*.py) $(wildcard scripts/*.py)

$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv $(PY_SRCS) | $(CLEAN_DIR)
python scripts/clean.py -i $< -o $@

並列実行と高速化

  • make -j により独立したファイル変換を並列化できる。データ点数が多いほど効果が高い。
  • 中間生成物を細かく分割するほど差分実行が効きやすく、全体の再計算を回避できる。
  • I/O がボトルネックの場合は圧縮形式やファイル分割、ローカル SSD などと併用する。

実運用のコツ

  • ディレクトリ作成は順序限定依存(| dir)で扱い、無駄な再ビルドを避ける。
  • 失敗時に不完全な生成物を残さないために .DELETE_ON_ERROR を有効化する。
  • よく使う入口を .DEFAULT_GOAL := all で標準化し、make 一発で動かせるようにする。
  • デバッグには make -n(実行せず表示)、make --trace(どの判定で動くか表示)、make -d(詳細ログ)を使う。
  • クリーンアップは .PHONY: clean とし、生成物だけを削除するよう注意する。

仮想環境と依存パッケージ(任意)

Python の実行環境も Make で管理できる。

VENV := .venv
PY := $(VENV)/bin/python

$(VENV)/bin/python: requirements.txt
python3 -m venv $(VENV)
$(VENV)/bin/pip install -r requirements.txt
touch $@

# 以降のレシピで $(PY) を使う
$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv scripts/clean.py | $(CLEAN_DIR) $(VENV)/bin/python
$(PY) scripts/clean.py -i $< -o $@

$(REPORT): $(CLEAN) scripts/aggregate.py | $(OUT_DIR) $(VENV)/bin/python
$(PY) scripts/aggregate.py -i $(CLEAN_DIR) -o $@

requirements.txt を更新すると必要な範囲でのみ再セットアップされる。

まとめ

  • Makefile は「依存関係の明示」と「差分だけの再実行」を自動化し、データ変換パイプラインの信頼性と開発速度を大きく向上させる道具である。
  • 元データ、スクリプト、生成物を正しく結び、処理を細かく分割することで、更新の影響範囲だけが素早く再計算される。
  • 最小の記述で再現性・並列化・可観測性が手に入り、日々の自動化作業が一段と快適になるのである。

WSL2 に Rocky Linux 8.10 をインストールする

WSL 2 イメージのダウンロード

https://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-Container-Base.latest.x86_64.tar.xz

ここからダウンロードする。

参考: https://docs.rockylinux.org/8/guides/interoperability/import_rocky_to_wsl/

イメージを展開

tar.xz を展開し、tar 形式にする。 tar にすることで、WSL2 へのインポートが可能となる。

cd ~/Downloads

xz -d Rocky-8-Container-Base.latest.x86_64.tar.xz

※Windows にインストール済みの bsdtar では展開不可。 ※xz コマンドがない場合は、cygwin64 でインストールするか、別の WSL ディストリビューションを用いて展開する。

イメージのインポート

WSL2 にイメージをインポートする。

wsl --import RockyLinux-8.10 $HOME .\Rocky-8-Container-Base.latest.x86_64.tar --version 2

イメージの確認

wsl -l -v

ユーザーの追加とデフォルトユーザーの設定

ユーザー名: hikari の場合

wsl -d RockyLinux-8.10 -u root -- dnf install sudo passwd -y

wsl -d RockyLinux-8.10 -u root -- adduser hikari

wsl -d RockyLinux-8.10 -u root -- passwd -d hikari

wsl -d RockyLinux-8.10 -u root -- usermod -aG wheel hikari

wsl -d RockyLinux-8.10 -u root -- sed -i 's/^# %wheel/%wheel/' /etc/sudoers

wsl -d RockyLinux-8.10 -u root -- echo -e "[user]\\ndefault=hikari" `| tee -a /etc/wsl.conf

イメージの起動

wsl -d RockyLinux-8.10

AlmaLinux 10 (Raspberry Pi 5 / GNOME / aarch64) に Mozc をインストールする方法

rpm ファイルをダウンロード

  • mozc
  • mozc-gui-tools
  • ibus-mozc

を検索し、rpmfind.net から検索してダウンロードする。

アーキテクチャが正しいかを確かめる。

  • Raspberry Pi 5 の場合は、aarch64
  • 一般的な PC の場合は、x86_64

rpm ファイルの例

  • mozc-2.31.5810.102-160000.1.2.aarch64.rpm
  • mozc-gui-tools-2.31.5810.102-160000.1.2.aarch64.rpm
  • ibus-mozc-2.31.5810.102-160000.1.2.aarch64.rpm

インストール

ダウンロードした rpm ファイルを指定し、dnf コマンドでインストールする。

cd ~/Downloads
sudo dnf install ./mozc-2.31.5810.102-160000.1.2.aarch64.rpm ./mozc-gui-tools-2.31.5810.102-160000.1.2.aarch64.rpm ./ibus-mozc-2.31.5810.102-160000.1.2.aarch64.rpm

ログアウト

一旦ログアウトする。

設定

「設定」→「キーボード」を開き、

  • Japanese (Mozc)
  • Japanese

の順に登録。

設定完了!

Rocky Linux 8.10 を WSL にインストールする

Rocky Linux 8.10 のイメージをダウンロードする

$dest = Join-Path $env:TEMP "Rocky-8-Container-Base.latest.x86_64.tar.xz"
Invoke-WebRequest -Uri "https://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-Container-Base.latest.x86_64.tar.xz" -OutFile $dest

インポート

wsl --import RockyLinux-8.10 $HOME $dest

passwd のインストール

wsl -d RockyLinux-8.10 -u root dnf update -y `&`& dnf install -y passwd

ユーザーの作成

$username = "hikari" # 好きなユーザー名を設定
wsl -d RockyLinux-8.10 -u root useradd -mG wheel $username
wsl -d RockyLinux-8.10 -u root passwd -d $username # ユーザーのパスワードを消去

sudo のインストール

wsl -d RockyLinux-8.10 -u root dnf update -y `&`& dnf install sudo -y

デフォルトユーザーの設定

$username = "hikari" # 好きなユーザー名を設定
$uid = wsl -d RockyLinux-8.10 id $username -u
if (-not $uid) {
Write-Error "UID の取得に失敗しました。ユーザー '$username' が存在しない可能性があります。"
exit 1
}

$basePath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss"

$targetKey = Get-ChildItem $basePath | Where-Object {
(Get-ItemProperty $_.PSPath).DistributionName -eq "RockyLinux-8.10"
}
if (-not $targetKey) {
Write-Error "DistributionName 'RockyLinux-8.10' が見つかりませんでした。"
exit 1
}

Set-ItemProperty -Path $targetKey.PSPath -Name "DefaultUid" -Value ([int]$uid)

EPEL の有効化

wsl -d RockyLinux-8.10 -u root dnf update -y `&`& dnf install -y epel-release

起動

wsl -d RockyLinux-8.10

デフォルトのディストリビューションにする場合

wsl --set-default RockyLinux-8.10

FastFetch のインストール

wsl -d RockyLinux-8.10 -u root dnf update -y `&`& dnf install fastfetch

FastFetch の実行

> wsl -d RockyLinux-8.10 -u root fastfetch
__wgliliiligw_, root@DESKTOP-MS-7C56-B550
_williiiiiiliilililw, -------------------------
_%iiiiiilililiiiiiiiiiii_ OS: Rocky Linux 8.10 x86_64
.Qliiiililiiiiiiililililiilm. Host: Windows Subsystem for Linux (2.0.14.0)
_iiiiiliiiiiililiiiiiiiiiiliil, Kernel: 5.15.133.1-microsoft-standard-WSL2
.lililiiilililiiiilililililiiiii, Uptime: 8 mins
_liiiiiiliiiiiiiliiiiiF{iiiiiilili, Packages: 285 (rpm)
jliililiiilililiiili@` ~ililiiiiiL Shell: bash 4.4.20
iiiliiiiliiiiiiili>` ~liililii Display 1: 1920x1080 @ 60Hz
liliiiliiilililii` -9liiiil Display 2: 1920x1080 @ 60Hz
iiiiiliiliiiiii~ "4lili WM: WSLg (Wayland)
4ililiiiiilil~| -w, )4lf Terminal: Windows Terminal
-liiiiililiF' _liig, )' CPU: AMD Ryzen 9 3900X (24) @ 3.800018 GHz
)iiiliii@` _QIililig, GPU: Microsoft Corporation Basic Render Driver
)iiii>` .Qliliiiililw Memory: 458.57 MiB / 62.76 GiB (0%)
)<>~ .mliiiiiliiiiiil, Disk (/): 51.72 GiB / 1007 GiB (5%)
_gllilililiililii~ Locale: C.UTF-8
giliiiiiiiiiiiiT`
-^~$ililili@~~' ████████████████████████
████████████████████████

AWS で公式 Rocky Linux イメージを使う

AMI の選び方

公式ページから AMI を入手します。

https://rockylinux.org/ja-JP/download

インスタンスに設定するアーキテクチャー (ARM (aarch64)) を選び、 Cloud Images の AWS AMI を選択。

alt text

バージョン番号でフィルターを掛け、条件にあったものを探す。

alt text

AMI ID はコピーできないので、デプロイボタンをクリックし、AWS コンソールからコピーする。

AMI ID で検索を掛けると、でてくる

alt text

所有者でフィルタリングしたほうが良いかも。

所有者 = 792107900819

alt text

事前準備

  • キーペアの登録
    • あらかじめ ssh-keygen -t ed25519 コマンドを実行て公開鍵を作成し、.ssh/id_ed25519.pub をキーペアにインポートしておく
  • AWS CLI の導入
    • CLI のインストール
    • アクセスキーの設定 (aws configure)

ネットワークを建てる

NAT ゲートウェイよりも、パブリック IP アドレスのほうが安いので、Elastic IP を作成。

図にするとこんな感じで建てる。

EC2 Instance Connect エンドポイントを作成

alt text

EC2 Instance Connect エンドポイントを作成することで AWS CLI からログインできる。

インスタンスを建てる

  • ping を要求を受け入れるため ICMP (エコー要求) を許可 (セキュリティグループ)
  • SSH 接続ができるようにこれを許可する (セキュリティグループ)
  • ムンバイリージョンと、arm64 が安い
  • vCPU あたり 1.5 GiB の RAM が必要 (最低でも t4g.medium)

というわけで、以下の条件で建てた。

  • ムンバイリージョン
  • アーキテクチャ: arm64
  • AMI: RHEL 8.10 (LVM, aarch64); ami-0415efd8380284dc4
  • インスタンスタイプ: t4g.medium
  • キーペア: PC で作った公開鍵 (.ssh/id_ed25519.pub)
  • ネットワーク: パブリックサブネット (インターネットゲートウェイへのルートが定義されているルートテーブルが関連付けされている)
  • セキュリティグループ: セキュリティグループを作成 (名前はデフォルト)
    • ssh, 0.0.0.0/0
    • カスタム ICMP - IPv4 (エコー要求), 0.0.0.0/0
  • ストレージ: 1x 10GiB, gp3

接続

PC のターミナルを開き、以下を実行。

aws ec2-instance-connect ssh --private-key-file .ssh/id_ed25519 --os-user rocky --instance-id i-*****************

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

Rocky Linux の AMI イメージには、Instance Connect パッケージがなく、マネジメントコンソールからの接続ができない。 そのため、パッケージをインストールする。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-connect-set-up.html を参考にパッケージをダウンロード。

  • ※RHEL のパッケージを選択
  • ※OS のメジャーバージョンやアーキテクチャーが違うと正常に動作しないので注意

curl https://amazon-ec2-instance-connect-us-west-2.s3.us-west-2.amazonaws.com/latest/linux_arm64/ec2-instance-connect.rhel8.rpm -o /tmp/ec2-instance-connect.rpm
curl https://amazon-ec2-instance-connect-us-west-2.s3.us-west-2.amazonaws.com/latest/linux_amd64/ec2-instance-connect-selinux.noarch.rpm -o /tmp/ec2-instance-connect-selinux.rpm
sudo dnf install -y /tmp/ec2-instance-connect.rpm /tmp/ec2-instance-connect-selinux.rpm

インストールが完了すると、マネコン上からアクセスできるようになる

alt text

CDK (typescript)

CDK 作ったので載せておく。参考までに。

keyName (キーペア) の名前は変えておく。

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

export interface RockyLinuxStackProps extends cdk.StackProps {
}

export class RockyLinuxStack extends cdk.Stack {
public constructor(scope: cdk.App, id: string, props: RockyLinuxStackProps = {}) {
super(scope, id, props);

// Resources
const ec2dhcpOptions = new ec2.CfnDHCPOptions(this, 'EC2DHCPOptions', {
domainName: 'ap-south-1.compute.internal',
domainNameServers: [
'AmazonProvidedDNS',
],
],
});
ec2dhcpOptions.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2InternetGateway = new ec2.CfnInternetGateway(this, 'EC2InternetGateway', {
{
value: 'igw',
key: 'Name',
},
],
});
ec2InternetGateway.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2vpc = new ec2.CfnVPC(this, 'EC2VPC', {
cidrBlock: '10.0.0.0/16',
enableDnsSupport: true,
instanceTenancy: 'default',
enableDnsHostnames: true,
{
value: 'vpc',
key: 'Name',
},
],
});
ec2vpc.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2VPCGatewayAttachment = new ec2.CfnVPCGatewayAttachment(this, 'EC2VPCGatewayAttachment', {
vpcId: ec2vpc.ref,
internetGatewayId: ec2InternetGateway.ref,
});
ec2VPCGatewayAttachment.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2NetworkAcl = new ec2.CfnNetworkAcl(this, 'EC2NetworkAcl', {
vpcId: ec2vpc.ref,
],
});
ec2NetworkAcl.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2RouteTable = new ec2.CfnRouteTable(this, 'EC2RouteTable', {
vpcId: ec2vpc.ref,
});
ec2RouteTable.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2SecurityGroup = new ec2.CfnSecurityGroup(this, 'EC2SecurityGroup', {
groupDescription: 'launch-wizard-1 created 2025-04-27T00:11:58.641Z',
groupName: 'launch-wizard-1',
vpcId: ec2vpc.ref,
securityGroupIngress: [
{
cidrIp: '0.0.0.0/0',
ipProtocol: 'tcp',
fromPort: 22,
toPort: 22,
},
{
cidrIp: '0.0.0.0/0',
ipProtocol: 'icmp',
fromPort: 8,
toPort: -1,
},
],
securityGroupEgress: [
{
cidrIp: '0.0.0.0/0',
ipProtocol: '-1',
fromPort: -1,
toPort: -1,
},
],
});
ec2SecurityGroup.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2Subnet = new ec2.CfnSubnet(this, 'EC2Subnet', {
vpcId: ec2vpc.ref,
mapPublicIpOnLaunch: false,
enableDns64: false,
availabilityZoneId: 'aps1-az1',
privateDnsNameOptionsOnLaunch: {
EnableResourceNameDnsARecord: false,
HostnameType: 'ip-name',
EnableResourceNameDnsAAAARecord: false,
},
cidrBlock: '10.0.0.0/20',
ipv6Native: false,
{
value: 'subnet-public1-ap-south-1a',
key: 'Name',
},
],
});
ec2Subnet.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2InstanceConnectEndpoint = new ec2.CfnInstanceConnectEndpoint(this, 'EC2InstanceConnectEndpoint', {
preserveClientIp: false,
securityGroupIds: [
ec2SecurityGroup.attrGroupId,
],
subnetId: ec2Subnet.attrSubnetId,
});
ec2InstanceConnectEndpoint.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2vpcdhcpOptionsAssociation = new ec2.CfnVPCDHCPOptionsAssociation(this, 'EC2VPCDHCPOptionsAssociation', {
vpcId: ec2vpc.ref,
dhcpOptionsId: ec2dhcpOptions.ref,
});
ec2vpcdhcpOptionsAssociation.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2RouteHg = new ec2.CfnRoute(this, 'EC2RouteHG', {
routeTableId: ec2RouteTable.ref,
destinationCidrBlock: '0.0.0.0/0',
gatewayId: ec2InternetGateway.ref,
});
ec2RouteHg.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2SubnetNetworkAclAssociation = new ec2.CfnSubnetNetworkAclAssociation(this, 'EC2SubnetNetworkAclAssociation', {
networkAclId: ec2NetworkAcl.ref,
subnetId: ec2Subnet.ref,
});
ec2SubnetNetworkAclAssociation.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2SubnetRouteTableAssociation = new ec2.CfnSubnetRouteTableAssociation(this, 'EC2SubnetRouteTableAssociation', {
routeTableId: ec2RouteTable.ref,
subnetId: ec2Subnet.ref,
});
ec2SubnetRouteTableAssociation.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2Instance = new ec2.CfnInstance(this, 'EC2Instance', {
tenancy: 'default',
instanceInitiatedShutdownBehavior: 'stop',
cpuOptions: {
threadsPerCore: 1,
coreCount: 2,
},
blockDeviceMappings: [
{
ebs: {
volumeType: 'gp3',
iops: 3000,
volumeSize: 10,
encrypted: false,
deleteOnTermination: true,
},
deviceName: '/dev/sda1',
},
],
availabilityZone: 'ap-south-1a',
privateDnsNameOptions: {
enableResourceNameDnsARecord: false,
hostnameType: 'ip-name',
enableResourceNameDnsAaaaRecord: false,
},
ebsOptimized: true,
disableApiTermination: false,
keyName: 'hikari',
sourceDestCheck: true,
placementGroupName: '',
networkInterfaces: [
{
privateIpAddresses: [
{
privateIpAddress: '10.0.3.59',
primary: true,
},
],
secondaryPrivateIpAddressCount: 0,
deviceIndex: '0',
groupSet: [
ec2SecurityGroup.ref,
],
ipv6Addresses: [
],
subnetId: ec2Subnet.ref,
associatePublicIpAddress: true,
deleteOnTermination: true,
},
],
imageId: 'ami-0415efd8380284dc4',
instanceType: 't4g.medium',
monitoring: false,
],
creditSpecification: {
cpuCredits: 'unlimited',
},
});
ec2Instance.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2ElasticIp = new ec2.CfnEIP(this, 'EC2ElasticIp', {
domain: 'vpc',
{
key: 'Name',
value: 'elastic-ip',
},
],
});
ec2ElasticIp.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;

const ec2EipAssociation = new ec2.CfnEIPAssociation(this, 'EC2EipAssociation', {
eip: ec2ElasticIp.ref,
instanceId: ec2Instance.ref,
});
ec2EipAssociation.cfnOptions.deletionPolicy = cdk.CfnDeletionPolicy.DELETE;
}
}

Hyper-V の Ubuntu にシリアルコンソールで接続する方法

VM の設定

「名前付きパイプ」を選択し、パイプ名を「COM1」に設定

Hyper-V Serial Settings

Ubuntu の設定

GRUB の設定

sudo nano /etc/default/grub で GRUB の設定ファイルを開き、

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash console=ttyS0,115200n8"

に変更する。

保存後、

sudo update-grub

で GRUB の設定を適用する。

シリアルポートの有効化

シリアルポートでログインできるようにサービスを設定する。

sudo systemctl enable serial-getty@ttyS0.service
sudo systemctl start serial-getty@ttyS0.service

接続

管理者権限で起動する

Tera Term から接続

Connect Serial port of Ubuntu on Hyper-V from Tera Term

PuTTY から接続

管理者権限で起動する

Serial lineSpeedConnection type:
\.\pipe\COM1115200Serial

に設定。

Connect Serial port of Ubuntu on Hyper-V from PuTTy

Connect Serial port of Ubuntu on Hyper-V from PuTTy

管理者権限で起動する

Connect Serial port of Ubuntu on Hyper-V from plink.exe on WindowsTerminal

[System.Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding("utf-8")
[System.Console]::InputEncoding = [System.Text.Encoding]::GetEncoding("utf-8")
plink.exe -serial \\.\pipe\COM1 -sercfg 115200,8,n,1,N

Ctrl + C で終了