Skip to content

Instantly share code, notes, and snippets.

@yonta
Last active August 23, 2025 07:22
Show Gist options
  • Save yonta/c1e341f644e7a1c0482a856a9533d08e to your computer and use it in GitHub Desktop.
Save yonta/c1e341f644e7a1c0482a856a9533d08e to your computer and use it in GitHub Desktop.
Initialize environment script for WSL with Ubuntu or openSUSE
#!/bin/bash -eu
# https://qiita.com/youcune/items/fcfb4ad3d7c1edf9dc96
# -euでエラーか未定義変数でストップする
# Color message
NORMAL=$(tput sgr0)
YELLOW=$(tput setaf 3)
GRAY=$(tput setaf 8)
function message() {
echo -e "$GRAY$*$NORMAL"
}
function header() {
echo -e "$GRAY##### $* ###############$NORMAL"
}
function warning() {
echo -e "$YELLOW$*$NORMAL"
}
########## Base Upgrade ##########
# Ubuntu japanese mirror repository
header "Ubuntu Japanese mirror repository"
codename=$(grep DISTRIB_CODENAME /etc/lsb-release | awk --field-separator '=' '{print $2}')
if [ ! -f "/etc/apt/sources.list.d/ubuntu-jp-mirror.sources" ]; then
message "Update Ubuntu repositories to Japanese mirror"
apt_sources="Types: deb
URIs: https://ftp.udx.icscoe.jp/Linux/ubuntu/
Suites: ${codename} ${codename}-updates ${codename}-backports ${codename}-security
Components: main universe restricted multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
Types: deb-src
URIs: https://ftp.udx.icscoe.jp/Linux/ubuntu/
Suites: ${codename} ${codename}-updates ${codename}-backports ${codename}-security
Components: main universe restricted multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
# Enabled: no
"
sudo sh -c "echo \"${apt_sources}\" > /etc/apt/sources.list.d/ubuntu-jp-mirror.sources"
message "Disabled default ubuntu.sources"
sudo sed --in-place '/Signed-By:/a Enabled: no' /etc/apt/sources.list.d/ubuntu.sources
fi
# Ubuntu Japanese Team repositories
header "Ubuntu Japanese Team repository"
if [ ! -f "/etc/apt/sources.list.d/ubuntu-ja.sources" ] &&
[ "${codename}" = "noble" ]; then # nobleまでサポート
message "Add Ubuntu Japanese Team repositories"
apt_sources="## Ubuntu Japanese LoCo Team's repository
## Please report any bugs to https://bugs.launchpad.net/ubuntu-jp-improvement
Types: deb
URIs: http://archive.ubuntulinux.jp/ubuntu/
Suites: ${codename}
Components: main
Signed-By: /etc/apt/keyrings/ubuntu-jp-ppa-keyring.gpg
Types: deb-src
URIs: http://archive.ubuntulinux.jp/ubuntu/
Suites: ${codename}
Components: main
Enabled: no
Signed-By: /etc/apt/keyrings/ubuntu-jp-ppa-keyring.gpg
Types: deb
URIs: http://archive.ubuntulinux.jp/ubuntu-ja-non-free/
Suites: ${codename}
Components: multiverse
Enabled: no
Signed-By: /etc/apt/keyrings/ubuntu-ja-archive-keyring.gpg
Types: deb-src
URIs: http://archive.ubuntulinux.jp/ubuntu-ja-non-free/
Suites: ${codename}
Components: multiverse
Enabled: no
Signed-By: /etc/apt/keyrings/ubuntu-ja-archive-keyring.gpg
"
sudo sh -c "echo \"${apt_sources}\" > /etc/apt/sources.list.d/ubuntu-ja.sources"
sudo wget https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -P /etc/apt/keyrings/
sudo wget https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -P /etc/apt/keyrings/
fi
# Update & Upgrade packages
header "Update & Upgrade packages"
sudo apt update
sudo apt full-upgrade -y
########## OS Configuration ##########
# XDG environment
export XDG_CONFIG_HOME="${HOME}/.config"
export XDG_CACHE_HOME="${HOME}/.cache"
export XDG_DATA_HOME="${HOME}/.local/share"
export XDG_STATE_HOME="${HOME}/.local/state"
# mkdir
header "Home directories"
if [ ! -d "${HOME}/.config" ]; then
message "Make XDG Base directories"
mkdir --parents "${XDG_CONFIG_HOME}" "${XDG_CACHE_HOME}" "${XDG_DATA_HOME}"
fi
if [ ! -d "${HOME}/git" ]; then
message "Make git and tmp directories"
cd "${HOME}"
mkdir --parents git tmp bin
fi
# ssh-key (First, because of user interaction)
header "SSH key"
keytype="ed25519"
if [ ! -f "${HOME}/.ssh/id_${keytype}" ]; then
message "Make ssh-key"
cd "${HOME}"
ssh-keygen -P '' -t ${keytype} -f "${HOME}/.ssh/id_${keytype}"
cat "${HOME}/.ssh/id_${keytype}.pub"
warning "Press [ENTER] to continue, after register SSH key to GitHub and BitBucket:"
read -r
fi
# Update locale
# language-pack-ja が必要
header "Locale"
if ! dpkg -s "language-pack-ja" > /dev/null 2>&1; then
message "Install language-pack-ja"
sudo apt install -y language-pack-ja
fi
if locale | grep 'LANG=' | grep -v 'ja_JP.UTF-8' > /dev/null 2>&1; then
message "Update Locale"
# If it is not Japanese environment now, this updates locale to Japanese
sudo update-locale LANG=ja_JP.UTF-8
message "LANG environment is set to Japanese."
warning "Press [ENTER] to continue, after running \`dpkg-reconfigure tzdata\` to change time zone Tokyo."
read -r
fi
# Write /etc/wsl.conf
header "wsl.conf"
if uname -a | grep '\-microsoft' > /dev/null 2>&1; then # WSL
message "Install wsl.conf"
# MEMO: Windows側の.exeファイルのみを実行権限付きにする方法がない。
# かといってfmask=113のようなxなしで使うとexeファイルが実行できず、
# wslviewなどが動かない。
# 残念だがすべて+x状態のファイルで取り扱う。
wslconf='[boot]
systemd = true
# command = service docker start
[automount]
options = "metadata,dmask=002,fmask=002"
[interop]
appendWindowsPath = false
[wsl2]
# memory = 16GB
# swap = 4GB
[user]
default = kei
'
sudo sh -c "echo \"${wslconf}\" > /etc/wsl.conf"
message "wsl.conf is updated"
fi
########## Install by apt ##########
# Install needed packages
header "base needed packages"
packages=(aptitude gitk build-essential autoconf automake unzip zip httpie jq
rlwrap clang direnv
fonts-vlgothic fonts-noto-cjk-extra fonts-noto-color-emoji
fonts-symbola
language-pack-ja manpages-ja manpages-ja-dev aptitude-doc-ja
markdown) # imagemagick graphviz
if uname -a | grep '\-microsoft' > /dev/null 2>&1 ; then # WSL
packages+=(x11-xserver-utils wslu)
if [ ! -f "/etc/apt/sources.list.d/wslutilities-ubuntu-wslu-${codename}.sources" ] ; then
# add-apt-repositoryがapt updateしてくれる
sudo add-apt-repository --yes ppa:wslutilities/wslu
fi
fi
if ! dpkg -s "${packages[@]}" > /dev/null 2>&1; then
message "Install packages"
sudo apt install -y "${packages[@]}"
fi
########## Install config ##########
# config
header "dotfiles"
if [ ! -d "${HOME}/git/config" ]; then
message "Clone config"
cd "${HOME}/git"
git clone [email protected]:yonta/dotfiles.git config
cd config
./sym_link.sh copy
mv "${HOME}"/.profile "${HOME}/.profile.orig"
message "Bash configuration files are linked."
fi
########## Install 3rd party apt packages ##########
# SML#
header "SML#"
if ! type smlsharp > /dev/null 2>&1; then
message "Add SML# repository"
# add-apt-repositoryがapt updateしてくれる
sudo apt-add-repository --yes ppa:smlsharp/ppa
message "Install SML#"
sudo apt install -y smlsharp
message "SML# is installed"
fi
# Install Dcoker
header "Docker"
if ! dpkg -s 'docker-ce' > /dev/null 2>&1; then
message "Install Docker dependencies"
packages=(ca-certificates curl)
if ! dpkg -s "${packages[@]}" > /dev/null 2>&1; then
sudo apt install -y "${packages[@]}"
fi
message "Add Docker GPG key"
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
message "Add Docker repository"
docker_source="Types: deb
URIs: https://download.docker.com/linux/ubuntu/
Suites: ${codename}
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
"
sudo sh -c "echo \"${docker_source}\" > /etc/apt/sources.list.d/docker.sources"
message "Install Docker comunity edition"
sudo apt update
sudo apt install -y docker-ce docker-compose-plugin
message "Docker is installed."
fi
# PostgreSQL library
header "PostgreSQL"
if ! dpkg -s 'libpq-dev' > /dev/null 2>&1; then
message "Install PostgreSQL keyring"
sudo curl -o /etc/apt/keyrings/pgdg.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
message "Add PostgreSQL repository"
pgdg_source="Types: deb
URIs: http://apt.postgresql.org/pub/repos/apt/
Suites: ${codename}-pgdg
Components: main
Signed-By: /etc/apt/keyrings/pgdg.asc
"
sudo sh -c "echo \"${pgdg_source}\" > /etc/apt/sources.list.d/pgdg.sources"
message "Install PostgreSQL dev files"
sudo apt update
sudo apt install -y libpq-dev
message "libpq-dev is installed."
fi
# GitHub CLI
header "GitHub CLI"
if ! type gh > /dev/null 2>&1; then
message "Add GitHub GPG key"
wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
message "Add GitHub repository"
gh_source="Types: deb
URIs: https://cli.github.com/packages/
Suites: stable
Architectures: amd64
Components: main
Signed-By: /etc/apt/keyrings/githubcli-archive-keyring.gpg
"
sudo sh -c "echo \"${gh_source}\" > /etc/apt/sources.list.d/github-cli.sources"
message "Install GitHub CLI"
sudo apt update
sudo apt install -y gh
message "gh is installed."
fi
########## Install by mise ##########
mise="${HOME}/.local/bin/mise"
if [ ! -f "${mise}" ]; then
message "Install mise"
curl https://mise.run | sh
message "Activate mise"
eval "$(${mise} activate bash)"
message "Activate mise completeions"
# completion に使う
${mise} use --global usage
eval "$(${mise} completions --include-bash-completion-lib bash)"
fi
if type mise > /dev/null 2>&1; then
message "Install by mise"
mise use --global \
act mold zig uv aws-cli aws-vault aws-copilot terraform tflint \
fzf biome rust-analyzer cloudflared ecspresso go hugo jq \
shfmt shellcheck hivemind hadolint ghalint actionlint yt-dlp \
[email protected] \
npm:typescript-language-server npm:typescript npm:ts-node \
npm:vscode-langservers-extracted npm:bash-language-server \
npm:elm npm:elm-format npm:elm-review npm:elm-test \
npm:@elm-tooling/elm-language-server \
npm:browser-sync npm:prettier \
npm:@anthropic-ai/claude-code
fi
########## Install by original script ##########
# Rust
header "Rust"
export CARGO_HOME="${XDG_DATA_HOME}/cargo"
export RUSTUP_HOME="${XDG_DATA_HOME}/rustup"
if [ ! -f "${CARGO_HOME}/bin/cargo" ]; then
message "Install Rust Dependencies"
sudo apt install -y libssl-dev pkg-config cmake bubblewrap
message "Install Rustup and Rust"
# プロンプト無しでbash設定ファイルを書き換えずに進む
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
message "Rust is installed."
fi
cargo="${CARGO_HOME}/bin/cargo"
if [ ! -f "${CARGO_HOME}/bin/bat" ]; then
message "Install Rust tools"
${cargo} install ripgrep --features "pcre2"
${cargo} install \
bat bottom cargo-update du-dust eza fd-find git-delta hyperfine \
pipr procs ripgrep_all starship tokei
message "Rust tools are installed."
fi
# shfmt が必要
if ! type batman > /dev/null 2>&1; then
message "Install bat-extras"
git clone --depth 1 https://github.com/eth-p/bat-extras.git \
"${HOME}/git/bat-extras"
cd "${HOME}/git/bat-extras"
# batのパスが通っていないとテストが落ちる対策
PATH="${CARGO_HOME}/bin:${PATH}"
./build.sh --minify=all --compress
sudo ./build.sh --minify=all --compress --no-verify --install
message "bat-extras is installed."
fi
# fzf
# Node
header "Node"
export NVM_DIR="${XDG_CONFIG_HOME}/nvm"
if [ ! -f "${NVM_DIR}/nvm.sh" ]; then
message "Install nvm"
# 特定のブランチのみdepth 1はできるが、タグは難しい。
# 具体的には空レポを作って、タグをdepth 1でfetch/checkoutするといけるらしい。
# 複雑なので採用せず、--depth 1なしcloneで最新tagを利用する。
git clone https://github.com/nvm-sh/nvm.git "${NVM_DIR}"
cd "${NVM_DIR}"
git checkout "$(git tags | sort --version-sort | tail --lines 1)"
message "NVM is installed."
fi
# HACK: クローンした状態ではnvm/versionsが存在しないのを利用
if [ ! -d "${NVM_DIR}/versions" ]; then
message "Install node"
# shellcheck disable=SC1091
. "${NVM_DIR}/nvm.sh"
nvm install --lts
message "Enable corepack"
corepack enable
# MEMO: npm install --global は使わず、mise use --global npm:[HOGE] で使う
message "Node is installed."
fi
# Ruby
header "rbenv"
export RBENV_ROOT="${XDG_DATA_HOME}/rbenv"
if [ ! -f "${RBENV_ROOT}/bin/rbenv" ]; then
message "Install rbenv"
git clone --depth 1 https://github.com/rbenv/rbenv.git "${RBENV_ROOT}"
message "Install rbenv plugins"
mkdir --parents "${RBENV_ROOT}/plugins"
git clone --depth 1 https://github.com/rbenv/ruby-build.git "${RBENV_ROOT}"/plugins/ruby-build
git clone --depth 1 https://github.com/ianheggie/rbenv-binstubs.git "${RBENV_ROOT}"/plugins/rbenv-binstubs
git clone --depth 1 https://github.com/meowsus/rbenv-clean "${RBENV_ROOT}"/plugins/rbenv-clean
message "rbenv is installed."
fi
if ! type rbenv > /dev/null 2>&1; then
message "Set up rbenv."
eval "$("${RBENV_ROOT}/bin/rbenv" init -)"
fi
header "Ruby"
if [ ! -f "${RBENV_ROOT}/shims/ruby" ]; then
message "Install Ruby dependencies"
# readline, for japanese input in REPL
if ! (dpkg-query --show "libreadline-dev" > /dev/null 2>&1 &&
dpkg-query --show "libyaml-dev" > /dev/null 2>&1 &&
dpkg-query --show "libpq-dev" > /dev/null 2>&1) ; then
sudo apt install -y libreadline-dev libyaml-dev libpq-dev libvips
fi
message "Install the latest Ruby"
# 最新バージョン番号、jruby/mrubyなどの文字列を省くようにしている
ruby_version="$(rbenv install --list | grep '^[0-9]' | sort --version-sort | tail --lines 1)"
rbenv install "${ruby_version}"
rbenv global "${ruby_version}"
message "Ruby is installed."
fi
if [ ! -f "${RBENV_ROOT}/shims/rubocop" ]; then
message "Install Ruby gems"
gem install yard
yard config --gem-install-yri
gem install solargraph --version 0.49.0
gem install rubocop rufo bundler_bash_completion \
solargraph-rails solargraph-rails-patch-for-rails71 solargraph-rspec \
seeing_is_believing irb htmlbeautifier
# yardのバグによりパターンマッチを含むとエラーする
# solargraphの補完情報にまだ使っている
# そのため、手動でyard gemsを実行する
# yard gems
message "Ruby gems are installed."
warning "Press [ENTER] to continue, after run \`yard gems\`."
fi
if [ ! -f "${HOME}/bin/git_rails" ]; then
message "Install git_rails"
wget --output-document "${HOME}/bin/git_rails" https://raw.githubusercontent.com/brysgo/git-rails/refs/heads/master/bin/git_rails
chmod +x "${HOME}/bin/git_rails"
message "git_rails is installed"
fi
########## Install by build source ##########
# Build cmigemo
header "cmigemo"
if ! type cmigemo > /dev/null 2>&1; then
message "Build and Install cmigemo"
sudo apt install -y nkf
cd "${HOME}/git"
git clone --depth 1 https://github.com/koron/cmigemo.git
cd "${HOME}/git/cmigemo"
./configure
make gcc
sudo make gcc-install
message "cmigemo is installed."
fi
# Build Emacs from source
header "Emacs"
emacs_version="30.1"
if ! type "emacs-${emacs_version}" > /dev/null 2>&1; then
mkdir --parents "${HOME}/tmp/emacs"
cd "${HOME}/tmp/emacs"
emacs_dir="${HOME}/tmp/emacs/emacs-${emacs_version}"
message "Download Emacs"
if [ ! -d "${emacs_dir}" ] &&
[ ! -f "${emacs_dir}.tar" ] &&
[ ! -f "${emacs_dir}.tar.xz" ]; then
wget http://ftp.jaist.ac.jp/pub/GNU/emacs/emacs-${emacs_version}.tar.xz
fi
if [ ! -d "${emacs_dir}" ] &&
[ ! -f "${emacs_dir}.tar" ]; then
xz -d "${emacs_dir}.tar.xz"
fi
if [ ! -d "${emacs_dir}" ]; then
tar xf "${emacs_dir}.tar"
fi
cd "${emacs_dir}"
message "Install Emacs dependencies"
sudo apt build-dep -y emacs
packages=(emacs-mozc-bin aspell-en) # gnome-tweaks libmagick++-dev
if ! dpkg -s "${packages[@]}" > /dev/null 2>&1; then
sudo apt install -y "${packages[@]}"
fi
message "Build and Install Emacs"
# WSL2でXwidgetを使うなら、libwebkit2gtk-4.0-devを入れて、
# export WEBKIT_FORCE_SANDBOX=0を設定し、
# --with-x-toolkit=gtk3 --with-xwidgetsでビルドする必要がある
./configure --without-selinux --with-x \
--with-native-compilation=aot --with-tree-sitter
# --with-imagemagick
make -j
sudo make install
message "Emacs is installed."
fi
if [ ! -f "${HOME}/bin/em" ]; then
message "Install em command"
wget --output-document "${HOME}/bin/em" https://raw.githubusercontent.com/susam/emfy/refs/heads/main/em
chmod +x "${HOME}/bin/em"
message "em is installed"
fi
if [ ! -f "${HOME}/bin/emacs-lsp-booster" ]; then
message "Install emacs-lsp-booster"
git clone --depth 1 https://github.com/blahgeek/emacs-lsp-booster.git \
"${HOME}/git/emacs-lsp-booster/"
cd "${HOME}/git/emacs-lsp-booster"
${cargo} build --release
cp target/release/emacs-lsp-booster "${HOME}/bin/"
message "emacs-lsp-booster is installed"
fi
if [ ! -f "${XDG_CONFIG_HOME}/emacs/lisp/hotfuzz-module.so" ]; then
message "Install native hotfuzz"
git clone --depth 1 https://github.com/axelf4/hotfuzz.git \
"${HOME}/git/hotfuzz"
cd "${HOME}/git/hotfuzz"
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS=-march=native \
&& cmake --build build
cp "${HOME}/git/hotfuzz/hotfuzz-module.so" "${XDG_CONFIG_HOME}/emacs/lisp/"
message "hotfuzz is installed"
fi
header "All is Done!!"
warning "Please restart bash."
# repl
ipython
# virutalize pip environment
virtualenv
# linter, reformatter
# flake8
# flake8-quotes
# autopep8
# importmagic3
# epc
# isort
# mypy type stub
# mypy
# data-science-types
# test
# pytest
# markdown
grip
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment