CLOVER🍀

That was when it all began.

npxコマンドを使って、未インストールのコマンドを使った時の挙動を確認する

これは、なにをしたくて書いたもの?

今まで、npxコマンドはローカルインストールされたnode_modules内の実行ファイルにパスを通して実行してくれるものだと思って
いたのですが、どうやら異なるようなのでちょっと確認しておきたいなと思いまして。

npxコマンド

そもそも、npxコマンドのドキュメントをちゃんと読んだことがなかったので、見てみます。

npx | npm Docs

ローカルにインストールされたnpmパッケージ、またはリモートからフェッチしたnpmパッケージから任意のコマンドをnpm runのように
実行できるコマンドというのが概要になっています。

This command allows you to run an arbitrary command from an npm package (either one installed locally, or fetched remotely), in a similar context as running it via npm run.

要求されたパッケージがローカルプロジェクトの依存関係にない場合は、npmキャッシュ内のフォルダにインストールされ、環境変数PATHに
追加するようです。

If any requested packages are not present in the local project dependencies, then they are installed to a folder in the npm cache, which is added to the PATH environment variable in the executed process.

実行したいコマンドとパッケージ名が一致しない場合は、--packageまたは-pで対象のnpmパッケージを指定する必要があります。

npm execというコマンドとも関連があるようです。

では、ちょっと試してみましょう。

環境

今回の環境は、こちら。

$ node --version
v16.16.0


$ npm --version
8.11.0


$ npx --version
8.11.0

ヘルプを見てみる

npxコマンドのヘルプを見てみます。

$ npx --help
Run a command from a local or remote npm package

Usage:
npm exec -- <pkg>[@<version>] [args...]
npm exec --package=<pkg>[@<version>] -- <cmd> [args...]
npm exec -c '<cmd> [args...]'
npm exec --package=foo -c '<cmd> [args...]'

Options:
[--package <pkg>[@<version>] [--package <pkg>[@<version>] ...]]
[-c|--call <call>]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[-ws|--workspaces] [--include-workspace-root]

alias: x

Run "npm help exec" for more info

npm execのヘルプに、より多くの情報があるようですね。

Run "npm help exec" for more info

どうやら、関連のあるコマンドのようです。

指示どおりに以下のコマンドを実行すると、もっと多くの情報が得られます。

$ npm help exec

npxのドキュメントに記載されているものの、npx --helpでは表示されないオプションもありましたし、

npx | npm Docs

より深く知ろうとすると、npm execのドキュメントを見るのが良いのでしょう。

npm-exec | npm Docs

パッケージ名とコマンド名が一致する場合

たとえば、create-react-appを使ってみます。

Getting Started | Create React App

npx create-react-appコマンドを実行。

$ npx create-react-app my-react-app

すると、create-react-appパッケージをインストールするかどうかを聞かれます。

Need to install the following packages:
  create-react-app
Ok to proceed? (y) 

yを入力すると、create-react-appコマンドが実行されます。

作成されたプロジェクト内に移動して

$ cd my-react-app

package.jsonを見てみます。

  "dependencies": {
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },

create-react-appパッケージは依存関係にはいなかったりします。

どこにあるかというと、$HOME/.npm/_npxディレクトリ内にあるようです。

$ ll $HOME/.npm/_npx/c67e74de0542c87c
合計 64
drwxrwxr-x  3 xxxxx xxxxx  4096  8月  3 01:17 ./
drwxrwxr-x  3 xxxxx xxxxx  4096  8月  3 01:16 ../
drwxrwxr-x 65 xxxxx xxxxx  4096  8月  3 01:17 node_modules/
-rw-rw-r--  1 xxxxx xxxxx 45128  8月  3 01:17 package-lock.json
-rw-rw-r--  1 xxxxx xxxxx    61  8月  3 01:17 package.json

package.jsonを見ると、こんな感じになっていました。

$HOME/.npm/_npx/c67e74de0542c87c/package.json

{
  "dependencies": {
    "create-react-app": "^5.0.1"
  }
}

なるほど、と。

ちなみに、パッケージのインストールを対話形式で聞かれないようにするのは、以下のように--yesまたは-yオプションを使います。

$ npx --yes create-react-app my-react-app


### または
$ npx -y create-react-app my-react-app

パッケージ名とコマンド名が一致しない場合

もうひとつ、NestJSで試してみましょう。

First steps | NestJS - A progressive Node.js framework

npx nestで実行してみようとするものの、エラーになりました。

$ npx nest new my-nestjs-app
npm ERR! could not determine executable to run

npm ERR! A complete log of this run can be found in:
npm ERR!     $HOME/.npm/_logs/2022-08-02T16_27_07_177Z-debug-0.log

パッケージ名と実行コマンド名が異なるので、解決できないからですね。

この場合、--packageまたは-pオプションを使用します。

$ npx --package @nestjs/cli nest new my-nestjs-app

### または
$ npx -p @nestjs/cli nest new my-nestjs-app

パッケージのインストールにyと答えれば、npxがパッケージをインストールして進んでいきます。

Need to install the following packages:
  @nestjs/cli
Ok to proceed? (y) 

--yesオプションを使用してもOKです。

$ npx --package @nestjs/cli --yes nest new my-nestjs-app

### または
$ npx -p @nestjs/cli -y nest new my-nestjs-app

完了したら、プロジェクト内に移動して作業をしていきます。

$ cd my-nestjs-app

なお、今回のnpxで自動的にインストールしたNestJSのCLIは、先ほどのcreate-react-appとはまた別のディレクトリにインストールされて
いました。

$ ll $HOME/.npm/_npx/ccf722f030a36e55
合計 204
drwxrwxr-x   3 xxxxx xxxxx   4096  8月  3 01:28 ./
drwxrwxr-x   4 xxxxx xxxxx   4096  8月  3 01:28 ../
drwxrwxr-x 199 xxxxx xxxxx  12288  8月  3 01:28 node_modules/
-rw-rw-r--   1 xxxxx xxxxx 182699  8月  3 01:28 package-lock.json
-rw-rw-r--   1 xxxxx xxxxx     56  8月  3 01:28 package.json

package.jsonの内容は、こちら。

$HOME/.npm/_npx/ccf722f030a36e55/package.json

{
  "dependencies": {
    "@nestjs/cli": "^9.0.0"
  }
}

だいたい、動作はわかりましたね。

ところで

ローカルまたはグローバルにインストールされていないパッケージは、npxコマンドでnpmキャッシュ内にダウンロードしてから実行する
ことができることを確認しました。

ところで、npmキャッシュにインストールしたパッケージは、結局npx経由だとグローバルインストールに近い状態にも見えるのですが、
どうなんでしょうね?

$ npx create-react-app --version
5.0.1


$ npx -p @nestjs/cli nest --version
9.0.0

定期的に削除したり、アップデートしたりした方がいいんでしょうか?

この話は、npm execコマンドのドキュメントで、キャッシュに関する注意事項として記載があります。

指定方法は、こんな感じでしょうか。

$ npx --package @nestjs/cli --yes --prefer-online nest new my-nestjs-app

個人的には、時々キャッシュを削除する、でいいかなと思わなくもないですが…。

Vagrantで使っているUbuntu Linux 22.04 LTSを日本語化する

これは、なにをしたくて書いたもの?

前に、こんなエントリーを書きました。

Vagrantで使っているUbuntu Linux 20.04を日本語化する - CLOVER🍀

Ubuntu Linux 22.04 LTSもリリースされましたし、VagrantのBoxも出ているのでこちらのエントリーと同様に日本語化から行ってみたいと
思います。

使用するVagrantのBoxは、こちらです。

Vagrant box generic/ubuntu2204 - Vagrant Cloud

自分がPCで主で使っているLinuxはUbuntu Linux 20.04 LTSのままなのですが、まずはVMからと。
PCで使っている方は、そのうちアップグレードするかどうか…ちょっと悩んでいます。

環境

今回の環境は、こちら。

$ vagrant version
Installed Version: 2.2.19
Latest Version: 2.2.19

You're running an up-to-date version of Vagrant!

使用するVagrant Boxのバージョン。

$ vagrant box list | grep ubuntu2204
generic/ubuntu2204 (libvirt, 4.1.2)

仮想マシンの起動と初期状態

まずはvagrant initをしてから

$ vagrant init generic/ubuntu2204

起動、SSHログイン。

$ vagrant up
$ vagrant ssh

パッケージの最新化だけしておきます。

$ sudo apt update
$ sudo apt upgrade
$ uname -srvmpio
Linux 5.15.0-43-generic #46-Ubuntu SMP Tue Jul 12 10:30:17 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux


$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:        22.04
Codename:       jammy


$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

最初の状態。

$ date
Tue Aug  2 01:04:59 PM UTC 2022


$ ll
total 36
drwxr-x--- 4 vagrant vagrant 4096 Aug  2 13:00 ./
drwxr-xr-x 3 root    root    4096 Jul 27 22:16 ../
-rw------- 1 vagrant vagrant   85 Aug  2 13:00 .bash_history
-rw-r--r-- 1 vagrant vagrant  220 Jan  6  2022 .bash_logout
-rw-r--r-- 1 vagrant vagrant 3775 Jul 27 22:24 .bashrc
drwxr-xr-x 2 vagrant vagrant 4096 Jul 27 22:24 .cache/
-rw-r--r-- 1 vagrant vagrant  807 Jan  6  2022 .profile
drwx------ 2 vagrant vagrant 4096 Aug  2 12:54 .ssh/
-rw-r--r-- 1 vagrant vagrant   13 Jul 27 22:24 .vimrc

ロケール。

$ env | grep LANG
LANG=en_US.UTF-8


$ locale
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=


$ localectl
   System Locale: LANG=en_US.UTF-8
       VC Keymap: n/a
      X11 Layout: us
       X11 Model: pc105

使えるロケールの一覧。

$ locale -a
C
C.utf8
en_US.utf8
POSIX

タイムゾーンの設定。

$ cat /etc/timezone
UTC


$ timedatectl
               Local time: Tue 2022-08-02 13:06:50 UTC
           Universal time: Tue 2022-08-02 13:06:50 UTC
                 RTC time: Tue 2022-08-02 13:06:50
                Time zone: UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Asia/Tokyoタイムゾーンはインストールされていました。

$ timedatectl list-timezones | grep Asia/Tokyo
Asia/Tokyo

manページの状態。

$ man grep
GREP(1)                                                                      User Commands                                                                     GREP(1)

NAME
       grep, egrep, fgrep, rgrep - print lines that match patterns

SYNOPSIS
       grep [OPTION...] PATTERNS [FILE...]
       grep [OPTION...] -e PATTERNS ... [FILE...]
       grep [OPTION...] -f PATTERN_FILE ... [FILE...]

DESCRIPTION
       grep  searches  for PATTERNS in each FILE.  PATTERNS is one or more patterns separated by newline characters, and grep prints each line that matches a pattern.
       Typically PATTERNS should be quoted when grep is used in a shell command.

       A FILE of “-” stands for standard input.  If no FILE is given, recursive searches examine the working directory, and nonrecursive searches read standard input.

       In addition, the variant programs egrep, fgrep and rgrep are the same as grep -E, grep -F, and grep -r, respectively.  These variants are deprecated,  but  are
       provided for backward compatibility.

OPTIONS
   Generic Program Information
       --help Output a usage message and exit.

〜省略〜

apt showを見た時の状態。

$ apt show grep
Package: grep
Version: 3.7-1build1
Priority: required
Essential: yes
Section: utils
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Anibal Monsalve Salazar <anibal@debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 508 kB
Provides: rgrep
Pre-Depends: libc6 (>= 2.34), libpcre3
Depends: dpkg (>= 1.15.4) | install-info
Suggests: libpcre3 (>= 7.7)
Conflicts: rgrep
Homepage: https://www.gnu.org/software/grep/
Task: minimal
Download-Size: 156 kB
APT-Manual-Installed: yes
APT-Sources: https://mirrors.edge.kernel.org/ubuntu jammy/main amd64 Packages
Description: GNU grep, egrep and fgrep
 'grep' is a utility to search for text in files; it can be used from the
 command line or in scripts.  Even if you don't want to use it, other packages
 on your system probably will.
 .
 The GNU family of grep utilities may be the "fastest grep in the west".
 GNU grep is based on a fast lazy-state deterministic matcher (about
 twice as fast as stock Unix egrep) hybridized with a Boyer-Moore-Gosper
 search for a fixed string that eliminates impossible text from being
 considered by the full regexp matcher without necessarily having to
 look at every character. The result is typically many times faster
 than Unix grep or egrep. (Regular expressions containing backreferencing
 will run more slowly, however.)

日本語化

では、日本語化していきます。

日本語ロケールの生成。

$ sudo locale-gen ja_JP.UTF-8


### または
$ sudo apt install language-pack-ja

localeの一覧に、ja_JP.UTF-8が追加されました。

$ locale -a
C
C.utf8
en_US.utf8
ja_JP.utf8
POSIX

LANGおよびLANGUAGE環境変数の設定。

$ export LANG=ja_JP.UTF-8
$ export LANGUAGE=ja_JP:

コマンドの結果が日本語になりました。

$ date
2022年  8月  2日 火曜日 13:12:04 UTC
vagrant@ubuntu2204:~$ ll
total 40
drwxr-x--- 4 vagrant vagrant 4096  8月  2 13:07 ./
drwxr-xr-x 3 root    root    4096  7月 27 22:16 ../
-rw------- 1 vagrant vagrant   85  8月  2 13:00 .bash_history
-rw-r--r-- 1 vagrant vagrant  220  1月  6  2022 .bash_logout
-rw-r--r-- 1 vagrant vagrant 3775  7月 27 22:24 .bashrc
drwxr-xr-x 2 vagrant vagrant 4096  7月 27 22:24 .cache/
-rw------- 1 vagrant vagrant   20  8月  2 13:07 .lesshst
-rw-r--r-- 1 vagrant vagrant  807  1月  6  2022 .profile
drwx------ 2 vagrant vagrant 4096  8月  2 12:54 .ssh/
-rw-r--r-- 1 vagrant vagrant   13  7月 27 22:24 .vimrc

システム全体の設定を変える場合。

$ sudo update-locale LANG=ja_JP.UTF-8 LANGUAGE=ja_JP:


### または
$ sudo localectl set-locale LANG=ja_JP.UTF-8 LANGUAGE=ja_JP:

シェルに再ログイン後、日本語化されます。

$ env | grep LANG
LANGUAGE=ja_JP:
LANG=ja_JP.UTF-8


$ localectl
   System Locale: LANG=ja_JP.UTF-8
                  LANGUAGE=ja_JP:
       VC Keymap: n/a
      X11 Layout: us
       X11 Model: pc105


$ locale
LANG=ja_JP.UTF-8
LANGUAGE=ja_JP:
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=

タイムゾーンの変更。

$ sudo timedatectl set-timezone Asia/Tokyo

確認。

$ cat /etc/timezone
Asia/Tokyo


$ timedatectl
               Local time: 火 2022-08-02 22:15:13 JST
           Universal time: 火 2022-08-02 13:15:13 UTC
                 RTC time: 火 2022-08-02 13:15:13
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

dateの結果も変わりました。

$ date
2022年  8月  2日 火曜日 22:15:28 JST

日本語manページのインストール。

$ sudo apt install manpages-ja manpages-ja-dev

manページが日本語化されました。

$ man grep
GREP(1)                                                                 General Commands Manual                                                                GREP(1)

名前
       grep, egrep, fgrep - パターンにマッチする行を表示する

書式
       grep [OPTIONS] PATTERN [FILE...]
       grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]

説明
       grep  は FILE で名前を指定されたファイルを検索して、与えられた PATTERN にマッチする部分を含む行を探します。 ファイルが指定されていない場合や、 ファイル名の代わ
       りに 1 個のマイナス記号 “-” が指定されている場合は、 grep は標準入力から検索します。 デフォルトでは、 grep はマッチした行を表示します。

       さらに、兄弟プログラム egrep と fgrep は、それぞれ grep -E と grep -F と同じです。 これらの兄弟プログラムは非推奨ですが、後方互換性のために用意されています。

オプション
   プログラムについての一般情報
       --help 使用法を出力して終了します。

〜省略〜

aptでの表示結果の日本語化。

$ sudo LANG=ja_JP.UTF-8 apt update

または、以下のファイルを作成して

/etc/apt/apt.conf.d/99translations

Acquire::Language "ja_JP";

apt update。

$ sudo apt update

日本語化されました。

$ apt show grep
Package: grep
Version: 3.7-1build1
Priority: required
Essential: yes
Section: utils
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Anibal Monsalve Salazar <anibal@debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 508 kB
Provides: rgrep
Pre-Depends: libc6 (>= 2.34), libpcre3
Depends: dpkg (>= 1.15.4) | install-info
Suggests: libpcre3 (>= 7.7)
Conflicts: rgrep
Homepage: https://www.gnu.org/software/grep/
Task: minimal
Download-Size: 156 kB
APT-Manual-Installed: yes
APT-Sources: https://mirrors.edge.kernel.org/ubuntu jammy/main amd64 Packages
Description: GNU grep, egrep, fgrep
 'grep' はファイル内の文字列を検索するユーティリティです。コマンドラインか
 ら、またスクリプトから使用できます。あなたが使用しないとしても、おそらくあ なたのシステムにある他のパッケージが使用するでしょう。
 .
 grep ユーティリティの GNU ファミリは "西洋最速の grep" かもしれません。GNU grep は、高速な遅延状態決定性照合器 (元祖
 Unix の egrep より約 2 倍速い) を 元に固定長文字列に対して Boyer-Moore-Gosper 検索を併用し、一致するはずのな
 い文字列を完全正規表現照合器で除いており、不必要なすべての文字の探索はしな いようになっています。このため、一般には Unix の grep や
 egrep より数倍高速 です (しかし後方参照を含む正規表現では他より遅くなるでしょう)。

apt updateでの日本語情報取得結果。

$ ll /var/lib/apt/lists/*-ja
-rw-r--r-- 1 root root 1820339  4月 22 02:16 /var/lib/apt/lists/mirrors.edge.kernel.org_ubuntu_dists_jammy_main_i18n_Translation-ja
-rw-r--r-- 1 root root   23071  4月 14 06:31 /var/lib/apt/lists/mirrors.edge.kernel.org_ubuntu_dists_jammy_multiverse_i18n_Translation-ja
-rw-r--r-- 1 root root 9141549  4月 22 02:16 /var/lib/apt/lists/mirrors.edge.kernel.org_ubuntu_dists_jammy_universe_i18n_Translation-ja

まとめ

Ubuntu Linux 22.04 LTSを日本語化してみました。

Ubuntu Linux 20.04 LTSと同じ手順で日本語化できましたが、こうやってやり直してみるといろいろ忘れていることがあるので、良い復習の
機会になりますね。