恥は/dev/nullへ by 初心者

プログラミング素人がのろのろと学んだことをつづっています♪

bashはどの設定ファイルを読み込むのか?

この記事の内容はDebian11(bullseye)環境にもとづいています。

目次


事の始まり(.local/binにパスが通っていない?)

bashの設定ファイルがどんな風に読み込まれるのか理解していなかったので、以下の出来事に遭遇しました。

システム上にはaptでインストールしたVimがありましたが、それとは別に自分でソースからビルドしたVimを試すために、ビルドしたファイルを~/.local/binに置きました。というのも、以前いずれかの設定ファイルで

if [ -d "$HOME/.local/bin" ] ; then
    PATH="$HOME/.local/bin:$PATH"
fi

#(コメント)
# if文の意味は「ホームディレクトリに .local/binというディレクトリ
# がある場合、%PATHよりも~/.local/binを優先してパスを通す」です

を見た記憶があったからです。そこで、~/.local/binにビルドしたVimファイルを置いておけば、aptでインストールされたVim(/usr/binにあるVim)ではなく、ビルドしたVimが起動すると思っていたのです。

しかし、ターミナルを開いてVimを起動したところ、aptでインストールしたVimの方が起動しました。

調べてみると、上述したif文は~/.profileに記述されていました。記述があるのに~/.local/binにパスが通っていないということは、ターミナルを起動した時に~/.profileは読み込まれていないということです。そこで、bashの設定ファイルがどんな風に読み込まれるのかを調べてみました。


この記事のポイント

この記事のポイントは次の2つです。

(1) bashがログインシェルとして起動したのか、インタラクティブシェルとして起動したのか

(2) (1)に記した各ケースにおいて、どの設定ファイルが読み込まれるか


ログインシェルとは? インタラクティブシェルとは?

ネット情報とmanページによると、bashがログインシェルとして起動したのかインタラクティブシェルとして起動したのかによって、bashが読み込む設定ファイルが異なるようです。では、ログインシェルとインタラクティブシェルとは何でしょうか?

ログインシェルについては

ログインシェル(login shell)とは、0番目の引数の最初の文字が - であるシェル、または --login オプション付きで起動されたシェルのことです。

とmanページに書かれています。参考にしたサイトには、bashがログインシェルとして起動する例として以下のものが載っていました。

su - [user]
bash --login
ssh user@host

1行目が「0番目の引数の最初の文字が - である」例のようです。2行目は「--login オプション付きで起動された」例です。3行目はsshでログインしている場面ですから、そのままログインシェルですね。

一方、インタラクティブシェルについては

対話的なシェルとは、オプションでない引数がなく、標準入力と標準エラー出力がいずれも端末に接続されていて(中略)、-c オプションが指定されていない状態で起動されたシェル、または -i オプション付きで起動されたシェルのことです。

とmanページに書かれています。参考にしたサイトには、bashインタラクティブシェルとして起動する例として以下のものが載っていました。

su [user]
bash

1行目の例を見た時、manページの「オプションでない引数がなく」という記述との関係で、「『su ユーザー名』としてもインタラクティブシェルとして起動するのだろうか?」という疑問を抱きましたが、後述する動作確認の結果を見るとインタラクティブシェルとして起動することが分かります。*1


余談ですが、ログインシェルでもインタラクティブシェルでもないケース(?)もありそうです。


ログインシェルが読み込む設定ファイル

manページの

bashが対話的なログインシェルとして起動されるか、--loginオプション付きの非対話的シェルとして起動されると、/etc/profileファイルが存在すれば、bashはまずここからコマンドを読み込んで実行します。このファイルを読んだ後、bashは~/.bash_profile, ~/.bash_login, ~/.profileをこの順番で探します。bashは、この中で最初に見つかり、かつ読み込みが可能であるファイルからコマンドを読み込んで実行します。

という記述から

・bashがログインシェルとして起動した場合
・bashが --login オプション付きで起動した場合

には

/etc/profileが存在すれば、これを読み込む。

その次に、

~/.bash_profile
~/.bash_login
~/.profile

という順序で探していく

という流れであると分かります。

ここで注意しなくてはならないのが、manページの以下の記述です。

bashは、この中で最初に見つかり、かつ読み込みが可能であるファイルからコマンドを読み込んで実行します。

「最初に見つかり」と書かれているように、.bash_profile、.bash_login、.profileの3つに関しては、3つ全てが読み込まれるわけではないということです。

Debian11で実験した所、次のように動作していました。

# ステップ 1
 .bash_profileが存在すれば .bash_profileを読み込んで終了
 (.bash_loginと.profileは読み込まれない)
 .bash_profileが存在しない場合、ステップ 2へ進む

# ステップ 2
 .bash_loginが存在すれば .bash_loginを読み込んで終了
 (.profileは読み込まれない)
 .bash_loginが存在しない場合、ステップ 3へ進む

# ステップ 3
 .profileが存在すれば、.profileを読み込む

つまり、読み込まれるのは3つのうち1つだけです(これらのファイルのどれかに残り2つのファイルも読み込むような細工をしておけば話は別ですが)。


インタラクティブシェルが読み込む設定ファイル

bashインタラクティブシェルとして起動した場合に関してはmanページに次のように書かれています。

ログインシェルでない対話的シェルとして起動されると、 ~/.bashrcファイル があれば、bashはここからコマンドを読み込み、実行します。

つまり、

bashがインタラクティブシェルとして起動した場合
~/.bashrcファイルが存在すれば、これを読み込む

ということです。裏を返して言えば、.bashrcが読み込まれた場合、bashインタラクティブシェルとして起動したということになります。


動作確認の前提

ここまで述べてきたことについてDebian上で動作確認をすることにしました。

まず、各設定ファイルが読み込まれた時に、そのファイルが読み込まれたと分かるようにecho文を記述しました。

/etc/profileファイルに    echo '/etc/profile was read'   と記述
~/.bash_profileファイルに echo '.bash_profile was read'  と記述
~/.bash_loginファイルに   echo '.bash_login was read'    と記述
~/.profileファイルに      echo '.profile was read'       と記述

/root/.profileファイルに  echo '.profile(root) was read' と記述


また、~/.profileにおいて

if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi

という部分をコメントアウトしておきました。このままだと.profileが読み込まれた時に.bashrcも読み込まれるので、bashがログインシェルとして起動したのかインタラクティブシェルとして起動したのか紛らわしいからです。

同じ理由で、rootのホームディレクトリにある.profileにおいて

if [ "$BASH" ]; then
  if [ -f ~/.bashrc ]; then
    . ~/.bashrc
  fi
fi

という部分をコメントアウトしておきました。

同時に、rootのホームディレクトリにある.bashrcに次のecho文を記述しました。

echo '.bashrc(root) was read'


それと、shoptコマンドを使用します。

shopt login_shell

を実行すると、ログインシェルとして起動した場合に

login_shell      on

と表示されます。
ログインシェルとして起動していない場合は

login_shell      off

と表示されます。


なお、先述したとおり、.bashrcが読み込まれた場合はbashインタラクティブシェルとして起動したと判断できます。これらを元に動作確認してみました。


動作確認1(ファイルの読み込み順序)

動作確認1では、bashがログインシェルとして起動した場合に、/etc/profile、.bash_profile、.bash_login、.profileがmanページの記載通りに読み込まれていることを確認します。

ホームディレクトリに .bash_profileと.bash_loginは無く .profileだけがある状況でDebianからログアウトし、再度ログインしました。画面には次のように表示されました。

/etc/profile was read
.profile was read

まず、存在すれば必ず読み込まれる/etc/profileが読み込まれ、その後 .profileが読み込まれていることが分かります。

次に、ホームディレクトリに .profileと .bash_loginがある状況でDebianからログアウトし、再度ログインしました。画面には次のように表示されました。

/etc/profile was read
.bash_login was read

これを見ると、.profileよりも先に探される.bash_loginがあったので、.bash_loginだけが読み込まれ、.profileが読み込まれていないことが分かります。

今度は、ホームディレクトリに .profile、.bash_login、.bash_profileがある状況でDebianからログアウトし、再度ログインしました。画面には次のように表示されました。

/etc/profile was read
.bash_profile was read

一番最初に探される.bash_profileが読み込まれ、.bash_loginと.profileは読み込まれていないことが分かります。


動作確認2(ログインかインタラクティブか)

動作確認2では、bashがログインシェルとして起動したのか、インタラクティブシェルとして起動したのか、もしくは、どちらでもないのかを見てみます。


<説明>
以下の動作確認例において赤文字になっている部分が実行したコマンドです。
なお、ホームディレクトリには .profileだけがある状態です(.bash_profileと.bash_loginはありません)。

<su - を実行し、shoptコマンドを実行>
$ su -
パスワード: (ここでrootのパスワードを入力)
/etc/profile was read
.profile(root) was read
# shopt login_shell
login_shell     on

bash --loginを実行し、shoptコマンドを実行>
$ bash --login
/etc/profile was read
.profile was read

$ shopt login_shell
login_shell     on

この2つのケースではshoptコマンド実行後に「login_shell on」と表示されているので、bashがログインシェルとして起動したことが分かります。

<su を実行し、shoptコマンドを実行>
$ su
パスワード: (ここでrootのパスワードを入力)
.bashrc(root) was read

# shopt login_shell
login_shell     off

.bashrcが読み込まれていることから、bashインタラクティブシェルとして起動したことが分かります。

次は、「オプションでない引数がなく」というmanページの記述との関係で気になっていたケースですが・・・。

動作確認をするために、pandaという一般ユーザーを作り、pandaのホームディレクトリの.bashrcには

echo '.bashrc(panda) was read'

と記述しました。

<su [user] を実行し、shoptコマンドを実行>
$ su panda
パスワード:(ここでpandaのパスワードを入力)
.bashrc(panda) was read

$ shopt login_shell
login_shell     off

この結果を見ると、bashインタラクティブシェルとして起動していますね。

bash を実行し、shoptコマンドを実行>
$ bash
.bashrc was read

$ shopt login_shell
login_shell     off

bashインタラクティブシェルとして起動しています。


最後にログインシェルでもインタラクティブシェルでもなさそうな(?)ケースです。

manページには、インタラクティブシェルとして起動するケースの1つとして「-c オプションが指定されていない状態で起動されたシェル」が載っています。-c オプションを試すために以下のスクリプトを用意しました。

#!/bin/bash

echo 'hoge'
shopt login_shell

このスクリプトhoge.shというファイル名で保存し、以下を実行しました。

bashに -c オプションを指定して実行し、shoptコマンドを実行>
$ bash -c ~/hoge.sh 
hoge
login_shell     off

この結果を見ると、.bashrcが読み込まれていないのでインタラクティブシェルではありません。同時に、「login_shell off」とあることから、ログインシェルでもありません。


おまけ(.bash_logout)

manページに.bash_logoutというファイルがどのタイミングで読み込まれるのか記述されていました。

ログインシェルが終了するときには、~/.bash_logoutファイルがあれば、bashはこれを読み込んで実行します。

そこで .bash_logoutに以下の記述をして動作確認をしてみました。

date "+%Y/%m/%d %T" > logout_time.txt


bash --loginを実行し、exitでログアウト>
$ bash --login
/etc/profile was read
.profile was read

$ exit
$ cat logout_time.txt
2023/05/12 01:09:02

確かにログインシェルが終了する時に.bash_logoutが読み込まれています。

ついでに、Xを終了し、コンソールで

exit

と入力してログアウトしました。その後、再ログインしてlogout_time.txtを開いてみたら、ログアウトした時点の時刻が記録されていました。

一方、「sudo systemctl poweroff」を実行してシステムをシャットダウンした場合に関しては、.bash_logoutは読み込まれていませんでした(logout_time.txtに時刻が記録されていませんでした)。


参考にしたサイト

以下のサイトを参考にさせていただきました。

(1) ログインシェル、インタラクティブシェルの見分け方(bash) - 朝から昼寝
(2) ログインシェルとインタラクティブシェルと~/.bashrc達の関係 - Qiita


残った疑問

manページに次の記述があります。

bashが対話的に動作している場合には、PS1が設定され、$- に i が含まれます。これを利用すると、対話的動作の状態であるかどうかを、シェルスクリプトや起動ファイルの内部で調べられます。


動作確認をしていた時、shoptコマンドの結果が「login_shell on」であると同時に、「PS1が設定されている」または「$-に i が含まれている」というケースがありました(echo $PS1 や echo $- で確認)。

この場合、「ログインシェルであって、インタラクティブシェルではない」とも「インタラクティブシェルであって、ログインシェルではない」とも言えません。そこで、自分勝手な解釈ですが「bashはログインシェルとして起動したけれど、対話的に動作しているということかな?」と考えておきました。

言い換えると、「インタラクティブシェルとして起動した」ということと「対話的に動作している」ということは別なのかな、という考え方です。

この点は疑問として残ったままです。しかし、bashをツールとして使うという観点で言えば、どのケースでどのファイルが読み込まれるのかが分かれば良いので、これといって問題は無いんですけれどね。

*1:後ほど、参考にしたサイトの(1)を読み返したら、「オプションでない引数(スクリプトファイル等)」という記載がありました。

lsの出力内容の色を変更する

ターミナルを開いてlsコマンドを使う時、ディレクトリの文字色が微妙に見づらいと感じました。そこで、色を変更する方法を調べてみました。

目次


.bashrcでLS_COLORSを設定する場合

たとえば、.bashrcに

export LS_COLORS='di=01;96'

と記述します。diはディレクトリ、01はBold体、96はターコイズを表しています。

.bashrcの編集が終わったら、ターミナルを閉じて、もう一度起動します(もしくは sourceコマンドで.bashrcを読み込みます)。

それから「ls --color=auto」を実行すると、ディレクトリの名前が「色はターコイズ、スタイルは太字」で表示されます。ただ、毎回 --color=auto を入力するのは手間なので、.bashrcにaliasを設定しておいた方が良いです。

alias ls='ls --color=auto'


ついでに、実行属性の付いたファイルを「色は明るい緑、スタイルは普通」にする場合、少し追記して以下のようにします。

export LS_COLORS='di=01;96:ex=00;92'

exは実行属性の付いたファイル、00はDefault、92は明るい緑です。


略語や番号の意味

diやex等の略語、色やスタイルに割り当てられている番号に関しては次のサイトの説明が参考になりました。

LS_COLORSの各項目の意味 - Qiita


このサイトによると「di」「ex」などはGNU coreutilsのソース(ls.cというファイル)に記述されているそうです。一部を以下に引用しておきます。

fi: File
di: Directory
ln: Symlink
pi: Pipe
so: Socket
bd: Block device
cd: Char device
mi: Missing file
or: Orphaned symlink
ex: Executable
do: Door
su: setuid
sg: setgid
st: sticky
ow: other-writable
tw: ow w/ sticky


上記サイトに載っていた色やスタイルの番号も引用しておきます。

# 色
30  Black
31  Red
32  Green
33  Orange
34  Blue
35  Purple
36  Cyan
37  Grey
90  Dark grey
91  Light red
92  Light green
93  Yellow
94  Light blue
95  Light purple
96  Turquoise
97  White

# 背景色
40  Black background
41  Red background
42  Green background
43  Orange background
44  Blue background
45  Purple background
46  Cyan background
47  Grey background
100 Dark grey background
101 Light red background
102 Light green background
103 Yellow background
104 Light blue background
105 Light purple background
106 Turquoise background
107 White background

# スタイル
00  Default colour
01  Bold
04  Underlined
05  Flashing text
07  Reversetd
08  Concealed


.colorrcでLS_COLORSを設定する場合

他に.colorrcを使った設定方法もあるようです。これについては以下のサイトが参考になります。

サーバ環境セットアップ|lsコマンドで表示される文字カラーを変更


このサイトを読みdircolors -pコマンドから.colorrcファイルを出力してみたところ、かなり細かく色設定ができるのだなと感じました。たとえば、「.tarファイルにはこの色、.pngファイルにはこの色」といった風に、拡張子ごとに色を設定することができそうです。ただ、私はそこまで頑張る気力がないのでやっていません(汗)。

sakuraのフォント変更

Debian11ではsakuraというターミナルを利用しているのですが、フォントを変更するやり方が分からなかったので調べてみました。


font行を変更する

ネット検索してみたら、以下のサイトが出てきました。
http://www.troubleshooters.com/linux/sakura.htm

このサイトにフォントの設定例が載っていたので、それを見て ~/.config/sakura/sakura.conf を編集しました。

編集の対象はfont=で始まる行です。

font=Ubuntu Mono,monospace 13

という行を次のように書き換えました。

font=HackGen Console,Regular 14

HackGen Consoleがフォント名、Regularがスタイル、14はフォントサイズです。


利用できるフォントの探し方

利用できるフォントを調べるには

fc-list

というコマンドを実行します。fc-listコマンドが出力した一覧に載っているフォントならば利用できます。

私の場合、HackGenというフォントを使うつもりで事前にインストールしておいたので、以下のようにしてHackGenが含まれている行だけを出力しました。

fc-list | grep HackGen | sort

出力された内容は次のとおりです。

/usr/share/fonts/HackGen/HackGen-Bold.ttf: HackGen:style=Bold
/usr/share/fonts/HackGen/HackGen-Regular.ttf: HackGen:style=Regular
/usr/share/fonts/HackGen/HackGen35-Bold.ttf: HackGen35:style=Bold
/usr/share/fonts/HackGen/HackGen35-Regular.ttf: HackGen35:style=Regular
/usr/share/fonts/HackGen/HackGen35Console-Bold.ttf: HackGen35 Console:style=Bold
/usr/share/fonts/HackGen/HackGen35Console-Regular.ttf: HackGen35 Console:style=Regular
/usr/share/fonts/HackGen/HackGenConsole-Bold.ttf: HackGen Console:style=Bold
/usr/share/fonts/HackGen/HackGenConsole-Regular.ttf: HackGen Console:style=Regular


この出力結果のうち、行末に近い部分を見ます。使うのは「:style」というワードの左側にあるフォント名と右側にあるstyleの種類です。

たとえば1行目には

HackGen:style=Bold

とあるので、このうち「HackGen」と「Bold」を次のように使用します。

font=HackGen,Bold 14

シンボリックリンクをコピーするには?

シンボリックリンクをコピーするには cp -d を使う

ビルドしたVim関係のファイルを ~/.local/binにコピーしようとして

cp * ~/.local/bin

としたら、シンボリックリンクが通常のファイルになってしまいました。以下は ls -l が出力した内容です。

# 元ファイル
lrwxrwxrwx (中略) eview -> vim
lrwxrwxrwx (中略) evim -> vim
lrwxrwxrwx (中略) ex -> vim
lrwxrwxrwx (中略) gview -> vim
lrwxrwxrwx (中略) gvim -> vim
lrwxrwxrwx (中略) gvimdiff -> vim
-rwxr-xr-x (中略) gvimtutor
lrwxrwxrwx (中略) rgview -> vim
lrwxrwxrwx (中略) rgvim -> vim
lrwxrwxrwx (中略) rview -> vim
lrwxrwxrwx (中略) rvim -> vim
lrwxrwxrwx (中略) view -> vim
-rwxr-xr-x (中略) vim
lrwxrwxrwx (中略) vimdiff -> vim
-rwxr-xr-x (中略) vimtutor
-rwxr-xr-x (中略) xxd

# ~/.local/binにコピーされたファイル
-rwxr-xr-x (中略) eview
-rwxr-xr-x (中略) evim
-rwxr-xr-x (中略) ex
-rwxr-xr-x (中略) gview
-rwxr-xr-x (中略) gvim
-rwxr-xr-x (中略) gvimdiff
-rwxr-xr-x (中略) gvimtutor
-rwxr-xr-x (中略) rgview
-rwxr-xr-x (中略) rgvim
-rwxr-xr-x (中略) rview
-rwxr-xr-x (中略) rvim
-rwxr-xr-x (中略) view
-rwxr-xr-x (中略) vim
-rwxr-xr-x (中略) vimdiff
-rwxr-xr-x (中略) vimtutor
-rwxr-xr-x (中略) xxd


ネット情報とmanページによると、cpコマンドに -d オプションを付ければ良さそうです。

cp -d * ~/.local/bin/

としてみたら、以下のようにシンボリックリンクのままコピーされました。

# cp -d を使って ~/.local/binにコピーされたファイル
lrwxrwxrwx (中略) eview -> vim
lrwxrwxrwx (中略) evim -> vim
lrwxrwxrwx (中略) ex -> vim
lrwxrwxrwx (中略) gview -> vim
lrwxrwxrwx (中略) gvim -> vim
lrwxrwxrwx (中略) gvimdiff -> vim
-rwxr-xr-x (中略) gvimtutor
lrwxrwxrwx (中略) rgview -> vim
lrwxrwxrwx (中略) rgvim -> vim
lrwxrwxrwx (中略) rview -> vim
lrwxrwxrwx (中略) rvim -> vim
lrwxrwxrwx (中略) view -> vim
-rwxr-xr-x (中略) vim
lrwxrwxrwx (中略) vimdiff -> vim
-rwxr-xr-x (中略) vimtutor
-rwxr-xr-x (中略) xxd


mvコマンドの場合

mvコマンドではオプション無しでシンボリックリンクのままファイル移動ができました。


素朴な疑問

cp -P でも同じことができそうです。cp -P を使ってコピーしてみたところ、シンボリックリンクのままコピーできました。

ただ、manページには

SYNOPSIS
       cp [OPTION]... [-T] SOURCE DEST
       cp [OPTION]... SOURCE... DIRECTORY
       cp [OPTION]... -t DIRECTORY SOURCE...


-d    same as --no-dereference --preserve=links

-P, --no-dereference
      never follow symbolic links in SOURCE

と書かれています。これを見ると--preserve=linksの有無が違うようです。

info cp

を見てみると

'-d'
     Copy symbolic links as symbolic links rather than copying the files
     that they point to, and preserve hard links between source files in
     the copies.  Equivalent to '--no-dereference --preserve=links'.

'-P'
'--no-dereference'
     Copy symbolic links as symbolic links rather than copying the files
     that they point to.  This option affects only symbolic links in the
     source; symbolic links in the destination are always followed if
     possible.

'-p'
'--preserve[=ATTRIBUTE_LIST]'
     Preserve the specified attributes of the original files.  If
     specified, the ATTRIBUTE_LIST must be a comma-separated list of one
     or more of the following strings:

     'mode'
          (省略)
     'ownership'
          (省略)
     'timestamps'
          (省略)
     'links'
          Preserve in the destination files any links between
          corresponding source files.  Note that with '-L' or '-H', this
          option can convert symbolic links to hard links.  For example,
               $ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
               74161745 a
               74161745 b
          Note the inputs: 'b' is a symlink to regular file 'a', yet the
          files in destination directory, 'c/', are hard-linked.  Since
          '-a' implies '--no-dereference' it would copy the symlink, but
          the later '-H' tells 'cp' to dereference the command line
          arguments where it then sees two files with the same inode
          number.  Then the '--preserve=links' option also implied by
          '-a' will preserve the perceived hard link.

          Here is a similar example that exercises 'cp''s '-L' option:
               $ mkdir b c; (cd b; : > a; ln -s a b); cp -aL b c; ls -i1 c/b
               74163295 a
               74163295 b

とあります。他にシンボリックリンクに関係する記述として以下の文章もありました。

   When copying from a symbolic link, 'cp' normally follows the link
only when not copying recursively or when '--link' ('-l') is used.  This
default can be overridden with the '--archive' ('-a'), '-d',
'--dereference' ('-L'), '--no-dereference' ('-P'), and '-H' options.  If
more than one of these options is specified, the last one silently
overrides the others.

   When copying to a symbolic link, 'cp' follows the link only when it
refers to an existing regular file.  However, when copying to a dangling
symbolic link, 'cp' refuses by default, and fails with a diagnostic,
since the operation is inherently dangerous.  This behavior is contrary
to historical practice and to POSIX.  Set 'POSIXLY_CORRECT' to make 'cp'
attempt to create the target of a dangling destination symlink, in spite
of the possible risk.  Also, when an option like '--backup' or '--link'
acts to rename or remove the destination before copying, 'cp' renames or
removes the symbolic link rather than the file it points to.


参考にしたサイト

シンボリックリンクのコピー | コマンドの達人

Gvimのインライン入力で困ったこと

Linux上のGvimで日本語を入力する時に困ったことが2つありました。


インライン入力できない

まず最初に困ったのは、そもそもGvimでインライン入力ができないことです。日本語入力をしてみたら、変換前の文字がインライン表示されず、別ウィンドウで表示されてしまいました。

これに関しては、gvimコマンドではなく

vim -g

Gvimを起動すれば良いという情報がネット上にありました。実際、そうしてみたらインライン入力できました。


変換前の文字が小さい

次に困ったのは、インライン入力時に表示される文字(変換前の文字)のサイズが小さいことです。こちらに関しては以下の記事が参考になりました。

https://github.com/vim-jp/issues/issues/1353

以下は上記記事からの引用です。

diff --git a/src/gui_xim.c b/src/gui_xim.c
index e45e1793f..a333c7c6f 100644
--- a/src/gui_xim.c
+++ b/src/gui_xim.c
@@ -251,7 +251,7 @@ im_preedit_window_open()
 #if GTK_CHECK_VERSION(3,16,0)
     {
        GtkStyleContext * const context
-                                 = gtk_widget_get_style_context(gui.drawarea);
+                                 = gtk_widget_get_style_context(preedit_label);
        GtkCssProvider * const provider = gtk_css_provider_new();
        gchar              *css = NULL;
        const char * const fontname
@@ -275,7 +275,7 @@ im_preedit_window_open()
            fontsize_propval = g_strdup_printf("inherit");
 
        css = g_strdup_printf(
-               "widget#vim-gui-preedit-area {\n"
+               "#vim-gui-preedit-area {\n"
                "  font-family: %s,monospace;\n"
                "  font-size: %s;\n"
                "  color: #%.2lx%.2lx%.2lx;\n"

この内容にしたがってVimソースコード gui_xim.c を一部編集しました。
ファイルの場所は以下のとおりです。

vim/src/gui_xim.c


このファイルの

GtkStyleContext * const context
              = gtk_widget_get_style_context(gui.drawarea);

という部分を

GtkStyleContext * const context
              = gtk_widget_get_style_context(preedit_label);

に変更します。

次に

css = g_strdup_printf(
    "widget#vim-gui-preedit-area {\n"
    "  font-family: %s,monospace;\n"

という部分を

css = g_strdup_printf(
    "#vim-gui-preedit-area {\n"
    "  font-family: %s,monospace;\n"

に変更します。

このファイルにもとづいてビルドすれば作業は終わりです。

ビルドが終わった後、vim -gで起動したgvimにおいてインライン入力を試したところ、変換前の文字は小さくなく見やすい状態になっていました。


その他

以下は、上述の作業をした際に調べた内容です。

対象は以下のとおりです。

(1)aptでDebianリポジトリからインストールしたもの
(2)ソース(gui_xim.c)に変更を加えずにビルドしたもの
(3)ソース(gui_xim.c)を変更してビルドしたもの


Vimの挙動(ターミナルで「vim」と入力して起動)

(1)インライン入力可能 / 変換前の文字のサイズは普通(小さくない)
(2)インライン入力可能 / 変換前の文字のサイズは普通(小さくない)
(3)インライン入力可能 / 変換前の文字のサイズは普通(小さくない)


Gvimの挙動(ターミナルで「vim -g」と入力して起動)

(1)インライン入力可能 / 変換前の文字のサイズは小さい 
(2)インライン入力可能 / 変換前の文字のサイズは小さい 
(3)インライン入力可能 / 変換前の文字のサイズは普通(小さくない)


なお、冒頭に記述したとおり、ターミナルで「gvim」と入力して起動したGvimでは(1)〜(3)いずれのケースにおいてもインライン入力できませんでした(変換候補が別ウィンドウで表示されました)。

Debian11でVim9.0をビルドしてみる

これまでDebianリポジトリからaptでインストールしたVimを使っていましたが、Versionが8.2でした。そこで、Vim9.0を使うためにビルドすることにしました。しかし、Vimのビルドは初めてなので、やり方を調べることから始めました。

作業は、vim-jpに記載されている説明とconfigure --help を見ながら行い、疑問があったらその都度ネット検索しました。

vim-jp » Linuxでのビルド方法


目次


ビルドに必要なものをインストール

まずはビルドに必要なツールや拡張(Perl拡張とかLua拡張とか・・・)に必要なものをインストールしました。インストールしたものは以下のとおりです。

build-essential autoconf automake cproto
gettext libtinfo-dev libacl1-dev libgpm-dev
libxmu-dev libgtk-3-dev libxpm-dev
libperl-dev python3-dev ruby-dev
libncurses-dev

# Lua拡張については以下のいずれかをインストール
(Luaを使う場合)
     lua5.4 liblua5.4-dev
(Luaの代わりにLuaJITを使う場合)
     luajit libluajit-5.1-dev

# sodium、sound、tclを有効にするために次の3つもインストール
libsodium-dev libcanberra-dev tcl-dev


Luaに関しては、ネット上にLuaJITの方が高速という話があったので、私はLuaJITを試すことにしました(後掲のconfigure実行例はLuaJITを使う前提となっています)。

libncurses-devについては、これがインストールされていない状態でconfigureを実行したら以下の文言が表示されたので、インストールしています。

checking for tgetent()... configure: error: NOT FOUND!
      You need to install a terminal library; for example ncurses.
      On Linux that would be the libncurses-dev package.
      Or specify the name of the library with --with-tlib.


vim-jpからの引用>

build-dep コマンドを使わずに、パッケージを個別にインストールするには以下を実行します。
$ sudo apt install git gettext libtinfo-dev libacl1-dev libgpm-dev
.
GCC等のビルドツールをまだインストールしていない場合は以下も実行します。
$ sudo apt install build-essential
.
gvim (GTK2 GUI版)をビルドするには以下も追加で必要です。(GUI版は一般的にはGTK2またはGTK3を使うのがよいでしょう。)
$ sudo apt install libxmu-dev libgtk2.0-dev libxpm-dev
.
Perl, Python2,3, Ruby拡張を使うには以下も追加で必要です。
$ sudo apt install libperl-dev python-dev python3-dev ruby-dev
.
Lua拡張を使うには以下も追加で必要です。
$ sudo apt install lua5.2 liblua5.2-dev
.
LuaJITのLua拡張を使うには代わりに以下も追加で必要です。
$ sudo apt install luajit libluajit-5.1
.
ソースコードを修正する場合は、以下のパッケージも必要になることがあります。
$ sudo apt install autoconf automake cproto


vim-jpに記述されているもののうち、python-devは我が家のDebian環境に見当たりませんでした。

apt search python

の結果を眺めてみると

python2-dev
python2.7-dev
python3-dev
python3.9-dev

の4つがありました。ここにpython-devが登場しなかったことと、python3-devがインストール済みだったことから、python-devは無視することにしました。


Vimのソースを取得する(and 必要に応じてコード修正)

Vimのソースをgitで取得します。

git clone https://github.com/vim/vim.git

なお、vim-jpに以下のアドバイスが載っていました。

git cloneを実行した後にソースが更新された場合は、以下のコマンドで最新のソースを取得できます。

$ git pull


必ずしも必要ではありませんが、私はGvimでインライン入力をする時に気になることがあり、この段階でソースコードの一部を修正しています(手順は以下の記事のとおり)。
Gvimのインライン入力で困ったこと - 恥は/dev/nullへ by 初心者


コンパイルとインストール

vim/srcディレクトリに移動します。

cd vim/src


configureを実行します。次の例では、ホームディレクトリの .localにインストールしようとしています。
それと、LuaJITを使うために --with-luajitオプションを含めています。LuaJITではなくLuaを使う場合、このオプションは不要です。

./configure --prefix=/home/hoge/.local --enable-multibyte --enable-cscope --enable-perlinterp --enable-python3interp --enable-rubyinterp --enable-luainterp --enable-fontset --enable-xim --enable-terminal --enable-fail-if-missing --with-luajit --with-x --enable-gui=gtk3 --enable-tclinterp

コンパイルしてインストールします。

make
make install

ここまでで作業は終わりです。この後に続く文章は試行錯誤のメモです。


configureをやり直す場合

オプションを変更してからビルドし直す場合は「make reconfig」を実行するとvim-jpに書かれていたのですが、なぜか上手く行きませんでした。

画面を見ると「make distclean」を実行しなさいと表示されていたので、次のようにしたらビルドが上手く行きました。

make distclean

./configure --prefix=/home/hoge/.local --enable-multibyte --enable-cscope --enable-perlinterp --enable-python3interp --enable-rubyinterp --enable-luainterp --enable-fontset --enable-xim --enable-terminal --enable-fail-if-missing --with-luajit --with-x --enable-gui=gtk3 --enable-tclinterp

make

make install


configureの内容

configureのヘルプを見るには次のようにします。

./configure --help


オプションの一部について調べてみました。

--with-features=huge      tiny, normal or huge (default: huge)
--enable-multibyte        Include multibyte editing support.
--enable-gpm              Use gpm (Linux mouse daemon). default=yes OPTS=yes/no/dynamic    これもdefaultがyes
--enable-cscope           Include cscope interface
--enable-gui=gtk3         X11 GUI. default=auto OPTS=auto/no/gtk2/gnome2/gtk3/motif/haiku/photon/carbon
--enable-perlinterp
--enable-tclinterp
--enable-python3interp
--enable-rubyinterp
--enable-luainterp
--with-luajit             Link with LuaJIT instead of Lua.
--enable-fontset          Include X fontset output support.
--enable-xim              Include XIM input support.
--enable-terminal         Enable terminal emulation support.
--enable-fail-if-missing  Fail if dependencies on additional features specified on the command line are missing.
--with-x                  use the X Window System

このうち

--with-features=huge
--enable-gpm

の2つはconfigure実行時に指定しませんでした。--with-featuresはデフォルトで hugeになると書かれていますし、--enable-gpmもデフォルトでyesになると書かれているからです。ただ、将来的にデフォルト値が変更されても困るので、明示的に指定しておいて良い気もします。

なお、ネット上では --enable-acl というオプションを指定している例がありましたがconfigureのヘルプに --enable-acl は記載されておらず、--disable-acl だけが載っていました。もしかしたら以前は--enable-aclが存在していたのかもしれません。

なお、--enable-aclを指定せずにビルドしましたが「+acl」になっていました。

<--enable-multibyte>
--enable-multibyteが何なのか分かりませんでしたが、Vimのヘルプにマルチバイトサポートという項目がありました。「中国語、日本語、韓国語などの」という記載があったので、2バイト以上の文字を扱うことを指しているものと想像します。

<XXXinterp>
ヘルプに以下の記述がありました。

--enable-perlinterp=OPTS     Include Perl interpreter.  default=no OPTS=no/yes/dynamic
--enable-python3interp=OPTS  Include Python3 interpreter. default=no OPTS=no/yes/dynamic
--enable-rubyinterp=OPTS     Include Ruby interpreter.  default=no OPTS=no/yes/dynamic
--enable-luainterp=OPTS      Include Lua interpreter.  default=no OPTS=no/yes/dynamic

これを読んで「=OPTS」を指定する必要があるのかなと思いましたが、vim-jpのビルド例ではOPTSを指定していませんでした。そこで、指定せずにconfigureとmakeを実行しました。これで問題はありませんでした。

なお、--enable-tclinterpも「=OPTS」を指定せずにconfigureとmakeを実行して問題ありませんでした。


sodium, sound, tclを有効にする

上述したconfigureオプション例は最終形で、その前には若干の失敗(?)もありました。

最初にビルドしたVimDebianリポジトリからaptでインストールしたVimを比較したところ、aptでインストールしたVimでは以下の3つが「+」(有効)になっているものの、ビルドしたVimでは「-」(無効)となっていました。

sodium
sound
tcl


<sodium>
sodiumについては、configureが出力した内容に次の記述がありました。

checking --enable-libsodium argument... Defaulting to yes
checking for libsodium... no; try installing libsodium-dev

この内容から、デフォルトでyesになるのでlibsodium-devをインストールするだけで良さそうです。

<sound>
configureのヘルプを見てもsoundに関するオプションが分かりませんでした。
しかし、ネット検索をしてみると「libcanberra」が関係していることが分かったので、libcanberra-devをインストールすることにしました。

<tcl>
configureのヘルプで--enable-tclinterpというオプションを見つけました。関係がありそうなパッケージをapt searchしてみたらtcl-devが見つかりました。


以上のことから「libsodium-dev」「libcanberra-dev」「tcl-dev」をインストールし、オプションに --enable-tclinterp を追加してconfigureすることにしました。


<作業内容>

sudo apt install libsodium-dev libcanberra-dev tcl-dev

cd vim/src

make distclean

./configure --prefix=/home/hoge/.local --enable-multibyte --enable-cscope --enable-perlinterp --enable-python3interp --enable-rubyinterp --enable-luainterp --enable-acl --enable-fontset --enable-xim --enable-terminal --enable-fail-if-missing --with-luajit --with-x --enable-gui=gtk3 --enable-tclinterp

make

make install


こうしてビルドし直したVimを調べたらsodium、sound、tclが有効になっていました。


LuaとLuaJITとlibncurses-dev

Luaを使う場合

Luaを使う場合、以下の2つを事前にインストールしておきます。

lua5.4
liblua5.4-dev

configureを実行する際、以下のオプションを使います

--enable-luainterp


Luaの代わりにLuaJITを使う場合

Luaの代わりにLuajitを使う場合、以下の2つを事前にインストールしておきます。

luajit
libluajit-5.1-dev

configureを実行する際、以下のオプションを使います

--enable-luainterp
--with-luajit


失敗談

LuaJITを使ってビルドした後、今度はLuaを使う想定でビルドし直してみました。そこで「LuaJITをアンインストール」→「configureを実行」としたら、以下のエラーが表示されました。

checking --with-luajit... yes
checking for luajit... no
checking if lua.h can be found in /usr/include... no
checking if lua.h can be found in /usr/include/lua... no
checking if lua.h can be found in /usr/include/moonjit-2.3... no
configure: error: could not configure lua

エラー内容から分かるとおり、原因は--with-luajitオプションを付けたままconfigureを実行してしまったことです。

libncurses-dev

libncurses-devがインストールされていない状態でLuaをインストールしてみました。

sudo apt install lua5.4 liblua5.4-dev

を実行したら、次のように表示されました。

以下の追加パッケージがインストールされます:
  liblua5.4-0 libncurses-dev libreadline-dev

提案パッケージ:
  ncurses-doc readline-doc

以下のパッケージが新たにインストールされます:
  liblua5.4-0 liblua5.4-dev libncurses-dev libreadline-dev lua5.4

理由は分かりませんがlibncurses-devlibreadline-devもインストールされました。

ドットファイルだけをlsするalias

環境を構築し直した際に.bashrcに記述しているaliasです。「こんな感じかな?」とややテキトーに書いていますので、間違っていたらご指摘ください。

alias lsdot='ls -a | grep "^\.[^.]"'
# もしくは
#  alias lsdot='ls -A | grep "^\."'

alias lldot='ls -Al | awk '\''$9 ~ /^\./ {print $0}'\'''
# もしくは
#  alias lldot='ls -al | awk '\''$9 ~ /^\.[^.]/ {print $0}'\'''


lsdotもlldotも(「.」と「..」以外の)ドットで始まる隠しファイルを一覧表示する時に使っています。


lldotの方はawkの一部をエスケープするために少しシングルクォーテーションが多いですが、シェルに手入力するとしたら次のようになります。

ls -Al | awk '$9 ~ /^\./ {print $0}'

もしくは

ls -al | awk '$9 ~ /^\.[^.]/ {print $0}'