だいぶ前に購入した新しいLinuxの教科書を再度読み返してみました。Linux自体は業務でも経験があって、ログなど人が書いたコードで学ぶことはあったのですが、改めて抜けているところや活用すれば効率化になるコマンド群をまとめたいと思い、本書の中からターミナルでbashを操作することを中心に経験も合わせて書いてます。本書でも、シェルの種類がbashで、個人的にもbashを利用しているのでbashを前提にまとめてます。
個人的な感覚だと、MacOSやWindowsでもbashは使用できるので、個人的にも Windows で git bash forwindows を使ってますし、繰り返しディレクトリ内を探索するファイル操作を行うとかであれば、活用できると思います。
Linuxの基本用語と覚えておきたいシェルの操作
Linux コマンド関連の用語を簡単に以下にまとめて見ました。
Linuxと呼ぶときに狭義のLinuxであるLinuxカーネルのことを指すのか、広義のLinux ディストリビューションのことを指すのかは注意が必要です。特に大半の方はLinuxを開発するというよりは、Linuxを操作する方だと思いますので、Linuxのコマンドに関するパス名展開やパイプラインなどのシェルの仕組みについては知っておきたいところです。
Linux カーネル | 狭義のLinux OSの中核、ハードウェア制御するソフトウェアのみを指す |
Linux ディストリビューション | 広義のLinux Linux カーネル + ユーザーが使用するコマンド群やアプリケーション |
シェル | ユーザとLinuxカーネルの橋渡しをするソフトウェアでユーザのコマンド入力を解釈して、Linuxカーネルに実行を依頼する |
ターミナルエミュレータ | コンピュータの操作をテキストベースで行うためのソフトウェアまたは環境で、Windows の Tera Term,Mac のターミナル,iTerm2 があります。 |
コマンドプロンプト | テキストベースのユーザーインターフェースで、ユーザーに対してコマンドを受け付け、実行結果を表示するソフトウェアまたは環境 |
コマンドライン | プロンプト($)の後ろに入力するコマンド部分のこと。 例: $ echo “文字列” の場合は「echo “文字列”」の部分 |
ターミナルマルチプレクサ | シェルを複数起動したい場合に、ターミナルを複数起動せずに、複数の仮想ターミナルを操作し、同時に複数のタスクを実行できるユーティリティ |
デリート(delete) | vim の名称でカット機能のこと |
ヤンク(yank) | vim の名称でコピー機能のこと |
プット(put) | vim の名称でペースト機能のこと |
パス名展開 | シェルに *(アスタリスク) を渡すと、Linuxカールネにコマンドが実行される前に対象のファイルの文字列に展開されて渡される。 |
拡張正規表現 | 基本正規表現に加えて、繰り返しを示すメタ文字「+ (1回以上)」「? (0回または1回)」などメタ文字の機能を拡張した正規表現 |
シェル
ここで重要なのはシェルです。ユーザーがターミナルでコマンドを打ち込んだ時の動作は以下のようになります。
- ユーザーがキーボード入力したコマンド(例: echo)を文字列として受け取る。
- そのコマンド名というファイルを探す
- そのコマンド名のファイルを実行する
- 実行した結果を標準出力として(ここではターミナル)に表示する
この時に、標準入力としてターミナルからコマンドを受け取り、そのコマンドを探す①②の部分はシェルが、③の実行する部分はLinuxカーネルがやっています。
つまり、シェルはユーザーとカーネルの間を橋渡しするカーネルのインターフェースとなっているソフトウェアです。
なぜカーネルとシェルが分かれているのかといえば、本書に書いてある通りでそれぞれの機能を明確に分離する目的であったり、シェルの種類がbash, zsh など複数あるのでカスタマイズ性の向上による側面です。
シェルのキーバインド
最低限知っておくと便利なシェルのキーバインドを紹介します。シェルによって多少の違いはあるが大きくは違いません。カーソルの移動系と、削除系、過去のコマンドの実行方法は覚えておくと良いでしょう。
これらは git bash や mac のターミナルでも使用できるため、ちょっとした作業でも使いこなせればそれなりに作業効率が上がります。カーソルの先頭、末尾に移動はキーボードのHomeでも移動できるため、ctrl+u や ctrl+r などはよく使用します。
Ctrl + a | カーソルを先頭に移動する |
Ctrl + e | カーソルを末尾に移動する |
Ctrl + w | カーソル前方の1単語を削除する |
Ctrl + u | カーソルから先頭までの文字列を削除する |
Ctrl + k | カーソルから末尾までの文字列を削除する |
Ctrl+y | 最後に削除した内容を挿入する |
Ctrl + r | コマンド履歴から検索する |
基本コマンド
一番よく使用するのはディレクトリの移動だと思いますが、そのほかにも基本的なファイル操作などは重要ですが、シェルの本領はパイプラインなどでシンプルなシェルのコマンドを組み合わせることですので、それぞれのコマンドの動作は一通り確認しておく必要があります。
※ 以下はLinuxではなく、Macでコマンドを打ち込んだ時の使用例です。Linuxで試して見たいときは、VirualBox、Windows の場合は git bash などでコマンドを試して見て下さい。
# Mac で実行したときの一例です。
$ printenv
PATH=/usr/local/opt/git/bin:
OLDPWD=/Applications/Eclipse_2023-06.app/Contents/workspace/
PWD=/Applications/Eclipse_2023-06.app/
LC_CTYPE=UTF-8
# エイリアスの設定
$ ailias <command>='<command> <option>'
# ls コマンド実行で常に -F オプションをつけて実行する(ls を ls -F で実行する)
$ ailias ls='ls -F'
# エイリアスの確認
$ type <command>
# エイリアスの削除
$ unailas <command>
# エイリアス設定済みのコマンドをエイリアスを無効にして実行する (ls の場合)
$ bin/ls
$ command ls
$ \ls
ファイルとディレクトリ操作
# ホームディレクトリへ移動 (引数なしでcdコマンドを実行)
$ cd
# または、チルダ(~)を使用する(チルダ展開)
$ cd ~
# 直前にいたディレクトリに移動する ($git switch - と似たような機能です)
$ cd -
ls コマンドは、指定したディレクトリのファイルやディレクトリを一覧表示するためのコマンドですが、パス名展開を使用したり、オプションをつけてファイルの情報を確認するためによく使用します。
パス名展開とは、ファイル名の一部をパターンで指定することで複数のファイル名を指定する方法です。ワイルドカード展開、ファイル名ブロブとも呼ばれます。注意することはここでの *(アスタリスク)は正規表現で使用するアスタリスクではないので、ファイル名やディレクトリ名の一部は置き換えられますが、サブディレクトまで含めたパスを置き換えられるわけではありません。
# カレントディレクトリの拡張子がjsのファイル名の一覧を表示する。
# ./hoge.js ./huga.js にはマッチするが、./hoge/hoge.js などサブディレクトリはマッチしない
$ ls ./*.js
# ファイルの詳細情報を表示する
$ ls -l
-rw-r--r--@ 1 user-name admin 1506 Sep 11 06:13 Xxxx-LICENSE.txt
drwxr-xr-x@ 4 user-name admin 128 Sep 11 06:13 apps
# ファイル種別を表示する
$ ls -F
Sample.txt bin@ docs/
Sample2.txt Xxxx-LICENSE.txt lib/
以下はファイル操作に関する基本コマンドです。
# 新規ファイルの作成
$ touch <file>
# ファイルの修正
$ vi <file>
# リダイレクトで文字列をファイルに書き込む
# ファイルがない場合は新規作成、ある場合は上書き
$ echo "書き込む文字列" > <file>
# 新規ディレクトリの作成
$ mkdir <directory>
# 存在しないディレクトリも含めてサブディレクトリを作成する
$ mkdir -p <directory>/<sub-directory>
# 行番号をつけてファイルの中身を表示する
# 引数にファイルを指定しない場合は標準入力としてキーボート入力が指定される
$ cat -n <file>
# ファイルをスクロール方式で表示する
$ less <file>
# file1 fil2 を directory にコピーする
$ cp <file1> <file2> <directory>
less や vi コマンドでファイルを開いたときにファイルの内容を検索する場合は以下の操作を行います。文字列を入力した後に Enter キーを押します。
コマンド | 内容 |
/<文字列> | 下方向に文字列にマッチする箇所を検索する |
?<文字列> | 下方向に文字列にマッチする箇所を検索する |
n | 次のマッチした検索結果に移動する |
N | 前のマッチした検索結果に移動する |
リンクの作成
ファイルやディレクトリのリンクを作成するとき、Windows では 「ショートカット」、Mac では「エイリアス」で作成するかと思います。Linux のコマンドではシンボリックリンクで同じ機能を持ったリンクを作成できます。
ハードリンクはほとんど使用しない機能ですが、ファイルの実体に対して複数のファイル名をつける機能です。シンボリックリンクはファイルの実体に対して参照を作成します。
# ハードリンクを作成する
$ ln <file1> <file2>
# シンボリックリンク
$ ln -s <file1> <file2>
ファイル・ディレクトリ検索
find コマンドは、指定したディレクトリを起点として再帰的にファイルを検索するコマンドです。*(アスタリスク)を使用してファイル名を指定する場合は必ず ”で囲む必要があります。クォートで囲まない場合は find コマンドが実行される前にシェルによりパス名展開が行われます。
# find コマンドのの基本的な構文
$ find <検索ディレクトリ> <検索条件> <アクション>
# <検索ディレクトリ>: .
# <検索条件>: -iname '*.txt':
# <アクション>: -print (省略可能した時に自動で指定される)
# -iname: 大文字小文字区別しない
$ find . -iname '*.txt' [-print]
# ''で囲わない場合
$ find . -iname *.txt
# file1.txt file.txt がある場合、「*.txt」→「file1.txt file.txt」に置き換えられて実行
$ find . -iname file1.txt file.txt
もう少し補足しておくと「find . -iname *.txt」というコマンドを入力するときの流れは次のようになります。
- find . -iname *.txt というコマンドをシェルが受け取る
- シェルがアスタリスクの部分をパス名展開して、この場合カレントディレクトリを指しているので、その中でマッチするファイル名(file1.txt file.txt)などに置き換える。
- 置き換えたコマンドを find . -iname file1.txt file.txt としてカーネルに渡す
つまり、アスタリスクを該当する文字列にマッチさせるという処理は同じなのですが、シェルが行うか、カーネルが行うかで処理が変わるわけです。
ファイル内から文字列にマッチする箇所を検索する
ファイル内から該当する文字列を検索するには、findコマンドと別の組み合わせて出力します。
# -type: ファイルにタイプを指定する
# f(ファイル),d(ディレクトリ),l(シンボリックリンク)
# ファイル内から文字列にマッチする箇所を検索する
$ find . -type f | xargs grep -nH "文字列"
find . -type f コマンドの結果として得られたファイル名にスペースや特殊文字が含まれている場合、xargs コマンドはそれを正しく処理できず、”unterminated quote” エラーが発生することがあります。
$ find . -type f | xargs grep -nH "Linux"
xargs: unterminated quote
1つ目は findの-print0オプションと、xargs の -0 オプションを使用する方法です。find コマンドの -print0 オプションと xargs コマンドの -0 オプションを使用することで、ヌル文字(ASCIIコードで0)を区切り文字として使用します。これにより、スペースや改行、その他の特殊文字を含むファイル名を安全に処理できます。
# find コマンドの -print0 オプションと xargs コマンドの -0 オプションを使用する
$ find . -type f -print0 | xargs -0 grep -nH "Linux"
2つ目はパイプラインを使用せずに、find の -exec オプションを使用する方法です。-exec オプションを使用する場合、{} の部分には find コマンドで見つかった各ファイル名が挿入されるため、スペースを含むファイル名でも正しく処理されます。
# -exec オプションを使用する
find . -type f -exec grep -nH "Linux" {} +
# -exec オプションの基本的な構文
find [検索場所] [検索条件] -exec [実行するコマンド] {} \;
3つ目はシェルスクリプト風に書くやり方です。
IFSは、Internal Field Separator; 内部フィールド区切り文字という環境変数で、bash が単語の区切りとして解釈する文字列が含まれています。デフォルト値は「スペース」「タブ」「改行」です。
find の標準出力をパイプラインで標準入力にします。while 内でfile変数に格納してから、grepします。
# while ループと read コマンドを使用する
$ find . -type f | while IFS= read -r file; do grep -nH "Linux" "$file"; done
IFSを変更すると、それ以降のコマンドも直に影響を受けるため、シェルスクリプなどで使う場合には最初に別のバックアップ用の変数に格納するなど注意が必要です。
ファイル・ディレクトリを削除する
ファイルやディレクトリを削除する場合は rm コマンドを使用します。
※ 間違ってファイルを削除をしないように試す場合は自己責任で実行して下さい。
# カレントディレクトリから再帰的に拡張子が特定のファイルをすべて削除する
# 拡張子が .rej のファイルをすべて削除する
$ rm $(find . -iname "*.rej")
# *(アスタリスク)は正規表現ではなく、パス名展開なので以下はうまくいきません
$ rm ./*.rej
# 指定したディレクトリを強制削除する
$ rm -rf <directory-name>
過去に実行したコマンドを実行する
普段よく使うコマンドは繰り返し使用するので過去に実行した
# 過去の検索履歴を実行する
# 実行する文字列の一部を入植してCtrlを押したままrを繰り返せば1つずづ過去の検索を辿れます
Ctrl + r
# (reverse-i-search)`':
# 過去のコマンド履歴を表示する
$ history
# 過去のコマンドをコマンド履歴の番号を指定して実行する
$ !履歴番号
テキスト処理は以下です。
# cut: 入力の一部を切り出す(csv で特定のカラムを抜き出す場合、一覧を表示させるのは tr)
$ cut -d <区切り文字> -f <取り出す番号> [<ファイル名>]
# tr: 入力に含まれる文字の一部を置換する
$ tr -- h
usage: tr [-Ccsu] string1 string2
tr [-Ccu] -d string1
tr [-Ccu] -s string1
tr [-Ccu] -ds string1 string2
# Macで「:」を改行に置換して環境変数を表示する
$ printenv PATH | tr ":" "\n"
/usr/local/opt/git/bin
/Library/Frameworks/Python.framework/Versions/3.7/bin
/usr/local/bin
/System/Cryptexes/App/usr/bin
/Library/Frameworks/Mono.framework/Versions/Current/Commands
/Library/PostgreSQL/13/bin
正規表現は以下です。
$ grep [オプション] <検索パターン> <ファイル名>
拡張正規表現について、ChatGPT に聞いてみました。
拡張正規表現(Extended Regular Expression、ERE)は、正規表現(Regular Expression、RE)の一種で、通常の正規表現よりも多くの表現力を持つものです。拡張正規表現は、文字列のパターンマッチングや検索、置換などの操作に使用されます。
拡張正規表現は、通常の正規表現に比べて以下のような特徴を持ちます:
- メタ文字の拡張: 拡張正規表現では、通常の正規表現よりも多くのメタ文字や特殊文字をサポートします。例えば、
+
(1回以上の繰り返し)、?
(0回または1回の繰り返し)、|
(論理OR)、()
(グループ化など)などが使用できます。- グループ化とバックリファレンス: 拡張正規表現では、正規表現の一部をグループ化し、そのグループを後で参照するバックリファレンスがサポートされています。これにより、特定の部分文字列をキャプチャしたり、置換操作で再利用したりできます。
- 非キャプチャグループ: キャプチャせずにグループ化するための
(?: ... )
構文が使えます。- 複数のエスケープシーケンス: 拡張正規表現では、エスケープシーケンスが増え、特殊文字をリテラルとして扱うことができます。
- 選択と量指定子:
|
を使用して選択肢を指定したり、{n,m}
のような数量指定子を使用して繰り返しの範囲を指定したりできます。
暗号化
あまり使用する機会はないかもしれませんが、ファイルをzipで暗号化するコマンドを紹介しておきます。
# ディレクトリをzip形式で暗号化する
# [-e | --encrypt] [-r | --recurse-paths]
$ zip -er "result-name.zip" "target-directory"
エイリアスの設定
find 系などよく使うけどオプションが長い系のコマンドはエイリアスにしておくが便利です。
# エイリアスの設定
$ alias ls='ls -1F'
$ find . -type f | xargs grep -nH "文字列"