ものづくりのためのLinux講座【シェルとターミナル操作】

スポンサーリンク
Shell and Terminal

本記事は「ものづくりのためのLinux講座」のうちシェルとターミナル操作に関する内容です。

シェルとターミナルについて網羅的知識を身につけることを目的としておらず、Linuxのターミナルを使う上で、一般的で効率的な操作方法を身につけるための基礎知識を紹介します。

Linuxを使う上でターミナル操作は欠かせません。

各種コマンドの実行やインストールなど、基本的にターミナルから実行することがほとんどなので、ターミナル操作に慣れておくことはLinuxを快適に使う上で必須のスキルと言えます。

ターミナルってただコマンドを打ち込んでEnter押すだけでしょ?と思いますよね?

はい、その通りではあるのですが、コマンド入力を補助する機能がいろいろあって、それを使いこなすとコマンド文字列を愚直に入力するよりも速く快適に操作することができます。

シェル

さて、ここまでターミナル操作に慣れることが必要と書いてきましたが、タイトルにあるシェルとは一体何なのか、気になりますよね?

Linuxにおいて、プログラムの実行やメモリ管理などはカーネルというプログラムが担っているのですが、シェルはカーネルとユーザの間を仲介してくれるプログラムです。

シェルは、ユーザが入力したコマンドを受け取ってカーネルに実行を依頼し、実行結果を受け取ってターミナルに表示する、といったことをしてくれます。

ターミナルを立ち上げると以下のような文字列が表示されて、その右にコマンド入力できる状態になります。

user@machine:~$

これはコマンドプロンプトと呼ばれ、シェルが入力待ちになっていることを表します。

コマンドプロンプトは環境によって異なるため、以降$のみで表現します。

コマンド実行を真似る際は、コマンドプロンプト(行頭の$)は入力する必要が無いことにご注意ください。

つまり、ターミナルを立ち上げるとシェルが起動して入力待ち状態になり、そのシェルに対してコマンドを渡していたということになります。

例えば、以下のようにlsコマンドを実行すると、カレントディレクトリ(今いるディレクトリ)に存在するファイルとディレクトリが表示されます。

$ ls

これは、入力された文字列lsをシェルが解釈して、カーネルにlsコマンドの実行依頼をしてくれていたのです。

さて、ここまでシェルのことを単にシェルと呼んでいましたが、実はシェルにはいくつも種類があります。

有名なのはbash(バッシュ)、zsh(ズィーシェル)、tcsh(ティーシーシェル)などですが、他にも多数あります。

自分が使っているシェルは何なのか、以下のコマンドを実行することで確認できます。

$ echo $SHELL
/bin/bash

echoは文字列を表示するコマンドで、引数に$SHELLを与えており、これは環境変数SHELLの中身を表示するという意味になります。

実行結果は環境によるのですが、上記はbashを使用している場合の例で、シェルプログラムのパスが表示されます。

パス

パスとは、Linuxにおけるファイルの住所です。

パスは、/(スラッシュ)から始まり、/を区切り文字として以下のように表現されます。

  /ディレクトリ1/ディレクトリ2/…/ファイル名(またはディレクトリ名)

ディレクトリは、Windowsでのフォルダのことです。

Windowsでのパスは、C:¥などから始まって区切り文字が¥であり、Linuxとは違いがあります。

単に/とすると、最上位のディレクトリのことを表し、ルートディレクトリと呼ばれます。

上記で説明したのは、パスの先頭が/となる絶対パス表現となります。

絶対パスはフルパスと呼ばれることがあります。

これに対し、先頭が/から始まらない相対パス表現という方法もあります。

例えば以下のlsコマンドは、カレントディレクトリ(今いるディレクトリ)に存在するabcというディレクトリまたはファイルをリストアップするという意味になります。

$ ls abc

カレントディレクトリは.(ドット)で表すことができ、以下のように./を付けて明示的に表現することもできます。

$ ls ./abc

1つ上のディレクトリは..(ドットドット)で表すことができ、例えば1つ上にあるxyzというディレクトリの下にあるファイルをリストアップしたい場合、以下のようにします。

$ ls ../xyz

このように、絶対パス表現では必ずルートディレクトリ/から始まり、相対パスではカレントディレクトリから見た相対的なパス表現になるという違いがあります。

コマンド入力

ターミナルでのコマンド入力の基本形は、以下のようになります。

コマンド名 [第1引数] [第2引数] [...]

上記のとおり、コマンド入力で最初に来るのはコマンド名になります。

[ 〜 ]としている部分は省略可能であることを表しています。

基本的なコマンドは「ものづくりのためのLinux講座【基本コマンド】」の記事で紹介しますので、ここではコマンドの詳細は説明しません。

例えば、以下のように入力した場合、ファイルの中身を表示するcatコマンドの第1引数にreadme.txtというファイルを与えて実行した、ということになります。

$ cat readme.txt

このコマンドを実行するとreadme.txtの中身がターミナルに表示されます。

ワイルドカード

以下は、grepコマンドの第1引数に-iというオプション、第2引数にabcという文字列、第3引数にtest*という文字列を与えて実行しています。

$ grep -i abc test*

シェルは、このような文字列を受け取ると、空白やタブを区切り文字としてコマンドと引数に分割し、カーネルに実行を依頼します。

上記コマンドのtestの後ろに付いている*(アスタリスク)はワイルドカードと呼ばれ、ファイル名がtestから始まる名前のファイルすべてを表すと解釈されます。

例えばカレントディレクトリにtest1.txttest2.txttest_123.shという3つのファイルがある場合、これらのファイル名に合致するため、以下のコマンドを実行したのと同じことになります。

$ grep -i abc test1.txt test2.txt test_123.sh

*を前につけて、*testとして前半部分を柔軟にしたり、*test*として一部にtestが入るファイルを対象にしたりできます。

ワイルドカードには*の他にもう1つ?(クエスチョンマーク)があり、こちらは任意の1文字を表します。

例えば、上記の場合と同様にカレントディレクトリにtest1.txttest2.txttest_123.shという3つのファイルがある場合に以下のコマンドを実行するとどうなるか見ていきます。

$ grep -i abc test?.txt

この場合、test?.txtは、test1.txttest2.txtの2つのファイルに合致するので、以下のコマンドを実行したのと同じになります。

$ grep -i abc test1.txt test2.txt

このように、ワイルドカードを使うことで複数ファイルを短い文字列で指定することができるので、コマンド入力を効率化できます。

また、?に似た機能で複数指定した文字の中の1文字を表現するための[ 〜 ]があります。

大カッコ内には、[aP3]のように複数文字を連続で書くことができ、これはaまたはPまたは3のうち1文字という意味になります。

ハイフンを使って範囲指定することもでき、[0-9]で数字1文字、[A-Za-z_]でアルファベットまたはアンダースコアのうち1文字となります。

*や?と組み合わせて使うこともでき、例えば以下のようにlsを実行すると、Aから始まり、数字.任意の1文字で終わるファイル名(Abcd5.oなど)の一覧が表示されます。

$ ls A*[0-9].?

ここで紹介した機能を一覧にまとめます。

意味
*任意の複数文字
?任意の1文字
[〜]複数指定した文字の中の1文字
例:[0-9]で数字、[A-Z_]でアルファベット大文字とアンダースコアのうち1文字

ワイルドカードは、正規表現と似ていますが異なります。特に正規表現での*は、直前の文字の0個または複数個の連続という意味になるので注意してください。

TABによる補完

使用するシェルによって多少動作が異なりますが、コマンドやファイル名は途中まで入力してTABキーを押すと補完したり、候補を表示したりできます。

例えばコマンドとしてsuまで入力してTABキーを押すと、以下のようにsuから始まるコマンドの候補が表示されると思います。

$ su
su            sudoedit      sudoreplay    sulogin       suspend
sudo          sudo_logsrvd  sudo_sendlog  sum

suから始まるコマンドの候補が複数あるので、それらが表示されています。

候補が1つしか無い場合は、コマンド名がすべて補完されて表示されます。

あとはコマンド引数の部分でTABを押すことでも同様にファイル名の補完や候補表示ができます。

長いファイル名の場合はすべて入力するのは大変なので、途中まで入力してTABによる補完機能を使うと入力の手間が省けます。

YouTube動画などで、Linuxに慣れている人のコマンド操作を見ていると、頻繁にTABキーを押していることに気づくと思います。

コマンド履歴の再利用

以下のコマンドで直前に実行したコマンドを再度実行することができます。

$ !!

これ以外にも直前のコマンドの第?引数(!:数値)や最後の引数(!$)などを再利用することができます。

例えば以下のように順に実行すると、最初のlsコマンドでfileA.txtfileB.txtの存在を確認し、続くcatの引数には!$を与えていて、これは直前のコマンドの最後の引数のことなので、cat fileB.txtとなり、fileB.txtの中身が表示されます。

$ ls fileA.txt fileB.txt
$ cat !$

第1引数であるfileA.txtを再利用する場合は、!:1または!^を使用します。

$ ls fileA.txt fileB.txt
$ cat !:1

引数すべてを再利用する場合は以下のようにします。

$ ls fileA.txe fileB.txt
$ cat !*

コマンドの実行履歴はhistoryコマンドで表示することができます。

$ history
 1  10:00   ls
 2  10:01   echo $SHELL
 3  10:05   cat readme.txt
 4  10:30   grep -i abc test*

historyコマンドの実行結果の一例として上記のようにコマンド実行履歴が表示されたとします。

このとき行頭の番号を使って以下のように再実行することができます。

$ !3

これは、履歴の中の3番目のコマンドcat readme.txtを再実行することになります。

なお、履歴の中の4番目のコマンドの第2引数をechoで表示したい場合、以下のように実行します。

$ echo !4:2
abc

4番目のコマンドの第2引数であるabcが表示されましたね。

同様に!4$とすると、履歴の4番目のコマンドの最後の引数を取り出すことができます。

$ echo !4$
test*

なお、履歴の番号はマイナスの数を指定することができ、2つ前のコマンドを実行したい場合は以下のようにします。

$ !-2

上記を一覧表にまとめると下表になります。

意味
!!直前のコマンド
!^直前のコマンドの第1引数
!$直前のコマンドの最後の引数
!*直前のコマンドの引数すべて
!:数値直前のコマンドの第n(数値)引数
!数値実行履歴のn(数値)番目のコマンド
!数値^実行履歴のn(数値)番目のコマンドの第1引数
!数値$実行履歴のn(数値)番目のコマンドの最後の引数
!数値*実行履歴のn(数値)番目のコマンドの引数すべて
!数値:数値実行履歴のn(数値)番目のコマンドの第m(数値)引数

上記につなげて:pとすることで、実行せずに表示のみの確認ができます。

例えば以下のようにすると、直前のコマンドを表示して、実行はされません。

$ !!:p

カーソル操作

ターミナルでのカーソルの移動や削除なんて説明されなくても、←→キー、Home/Endキー、BackSpace/Deleteキーだよね?という声が聞こえてきそうです・・・

確かにその通りなのですが、Linuxはキーボードのホームポジションから極力移動が少ない状態でいろいろなことができるように考慮されていて、下表の操作方法2のCtrlキーとの組み合わせでもカーソル移動や削除ができます。

また、↑キーまたはCtrl+Pでコマンド履歴を1つずつ戻って表示させることができ、↓キーまたはCtrl+Nでコマンド履歴を進める方向で表示させることができます。

操作方法1操作方法2
カーソルを左に移動Ctrl+B
カーソルを右に移動Ctrl+F
カーソルを一番左に移動HomeCtrl+A
カーソルを一番右に移動EndCtrl+E
カーソルの左の文字を削除BackSpaceCtrl+H
カーソル上の文字を削除DeleteCtrl+D
すべて削除Ctrl+U
カーソルから右を削除Ctrl+K
コマンド履歴を戻る方向で表示Ctrl+P
コマンド履歴を進む方向で表示Ctrl+N

Linuxでは矢印キーまで指を移動するよりは、Ctrlを押した状態で何かする方がキー入力の労力が小さいと考えて、このような機能が提供されています。

ここで、多くのキーボードではCtrlキーは左下付近の押しにくい場所にあり、Aキーの左の押しやすいところに、ほぼ使い道の無いCapsLockキーがあると思います。

LinuxにおいてCtrlキーは使用頻度の高い重要なキーですので、Aの左のキーをCtrlに置き換えることを強く推奨します。

やり方は、まず/etc/default/keyboardを管理者権限(sudoコマンド)で編集します。

$ sudo vi /etc/default/keyboard

viエディタの使い方がわからない方は、以下の動画を参考にしてください。

以下の行まで移動します。

XKBOPTIONS=""

“”の部分に以下のように”ctrl:nocaps”として保存終了します。

XKBOPTIONS="ctrl:nocaps"

以下のコマンドで再起動すると次回からCapsLockキーがCtrlキーになっているはずです。

$ sudo reboot

Aの左のキーをCtrlに置き換えることで、操作方法2は最大限効率的になり、慣れるとこちらの方が速く操作できるので、ぜひ練習してみてください。

CapsLockをCtrlに置き換える方法は以下の動画でも説明していますので、参考にしてください。

標準入出力

何らかのコマンドを実行して、ターミナルに実行結果が表示されるのは、実はコマンドが標準出力に出力した文字列をシェルが受け取って表示してくれていたということになります。

出力には、通常のログなどを出力するための標準出力と、エラーメッセージを出力するための標準エラー出力があります。

標準出力と標準エラー出力は、通常はターミナルに出力されますが、出力先をファイルにすることもできます。

また、標準入力もあり、これもターミナルから入力したり、ファイルからの入力にすることができます。

入出力をファイルに切り替えることはリダイレクトと呼ばれ、次の章で説明します。

リダイレクト

入出力をファイルに切り替えることをリダイレクトと言いますが、もっともよく使うのが標準出力をファイルに切り替えることです。

標準入出力には下表のとおり番号が振られていて、リダイレクト記号が用意されています。

番号リダイレクト記号
標準入力0<
標準出力1> または 1>
標準エラー出力22>

例えば、echoコマンドで表示した内容をファイルに出力する場合、以下のように実行します。

$ echo 'Hello World!' > hello.txt
$ cat hello.txt
Hello World!

echoコマンドの出力先はhello.txtというファイルにリダイレクトされているので、ターミナルには何も表示されませんが、catコマンドでhello.txtの中身を表示すると、このファイルにechoコマンドの結果が出力されていたことがわかります。

続いてエラー出力をファイルに出す例を紹介します。

例えば、lsコマンドの引数に存在しないファイル名xxxを与えると、以下のようにエラーメッセージが表示されます。

$ ls xxx   
ls: cannot access 'xxx': No such file or directory

このエラーメッセージが標準エラー出力に出ていることを確認するために>2>を使って次のように実行してみます。

$ ls xxx > std 2> err
$ cat std
$ cat err
ls: cannot access 'xxx': No such file or directory

>1>の省略形であり、標準入出力の1番である標準出力をstdというファイルに切り替え、標準入出力の2番である標準エラー出力をerrというファイルに切り替えてlsコマンドを実行しています。

Windowsでは、テキストファイルは.txtという拡張子にするなど、ツールと関連付けるための暗黙のルールのようなものがありますが、Linuxではファイル名は自由で、aaa.txtのような拡張子付きのスタイルにしても良いし、拡張子なしのファイル名でも構いません。

catコマンドでstdの中身を表示しても何も表示されません。

これは存在しないファイル名が指定され、エラーで止まってしまったためです。

errの方には、エラーメッセージが入っていることがわかります。

このように、標準出力と標準エラー出力を別々のファイルに分けて出力できます。

標準出力と標準エラー出力を1つのファイルに出力したい場合、2>&1として標準エラー出力の出力先を標準出力に切り替えることで実現できます。

$ ls xxx > both 2>&1
$ cat both
ls: cannot access 'xxx': No such file or directory

標準入力をファイルから行う方法を紹介します。

Hello World!と書かれたhello.txtというファイルがあるとき、以下のようにcatコマンドの標準入力をhello.txtに置き換えて実行すると、中身が表示されます。

$ cat < hello.txt 
Hello World!

catコマンドは標準入力としてhello.txtの中身を受け取り、それを表示したということになります。

さて、ここである程度Linuxを触ったことがある方なら、<なんて使わなくても以下のように書けば済むのでは?と思ったはずです。

$ cat hello.txt 
Hello World!

こちらも同じ結果になります。

これは、catコマンドが標準入力も受け付けるし、引数によるファイル指定も可能なコマンドであるため、両方の記述で同じ動作になりました。

パイプ

Linuxの多くのコマンドが標準入力を受け付けるようになっています。

|(パイプ)を使って、コマンドの標準出力を続くコマンドの標準入力につなげ、数珠つなぎで実行することができます。

例えば、ファイルの中身が以下であるtest.txtがあるとします。

bbb
123
aaa

このとき、|(パイプ)を使って次のようにgrepコマンドとsortコマンドを実行した場合を考えます。

$ grep '[a-z]' test.txt | sort
aaa
bbb

上記はgrepコマンドでtest.txtファイル中のアルファベット小文字が含まれる行のみ取り出し、その結果をsortコマンドに渡してアルファベット順に並べ替えるという内容です。

grepコマンドによりbbbとaaaの行が抽出され、パイプで渡されたsortコマンドがアルファベット順に並び替えて、aaa、bbbの順になって結果として出力されました。

grepの結果を一旦何らかのファイルに出力して、そのファイルを読み込んでsortを実行しても同じ結果になりますが、中間的なファイルを作らずに複数コマンドを数珠つなぎで実行できるのがパイプを使うメリットです。

バックグラウンド実行

単にコマンドを実行するとフォアグラウンド実行となり、コマンドが終了してから次のコマンドの実行が可能になります。

しかし、実行時間が長いコマンドを実行しておいて、待ち時間の間に別のことをしたいということがあります。

このとき役に立つのがバックグラウンド実行で、コマンドの最後に&を付けて実行します。

$ sleep 10 &
[1] 37513

sleep 10は10秒待つコマンドで、バックグラウンド実行すると、すぐに次のコマンドを実行できる状態になります。

jobsコマンドで実行中のバックグラウンドジョブを確認することができます。

$ jobs
[1]+  Running                 sleep 10 &

上記は実行中のバックグラウンドジョブが1つだけなので[1]としてsleep 10が表示されています。

複数実行中の場合、[2], [3]のように表示されます。

killコマンドの引数に%ジョブ番号(今回の例では1)を指定して、実行中のバックグラウンドジョブを終了させられます。

$ kill %1
$ jobs
[1]+  Terminated              sleep 10

killコマンド実行後にjobsで実行状態を確認すると、上記のようにTerminatedと表示され、途中終了させられたことがわかります。

一度、フォアグラウンドで実行した後にバックグラウンドに変更するには、Ctrl+Zでコマンドをサスペンドしたあと、bgコマンドでサスペンドしたジョブをバックグラウンドジョブにできます。

$ sleep 10
^Z
[1]+  Stopped                 sleep 10
$ bg
[1]+ sleep 10 &
$ jobs
[1]+  Done                    sleep 10

バックグラウンドジョブをフォアグラウンドにするにはfgコマンドを使います。

$ sleep 10 &
[1] 39362
$ fg %1
sleep 10

Ctrl+Zでサスペンドしたジョブをフォアグラウンドで再開するには、引数無しでfgコマンドを実行します。

$ sleep 10
^Z
[1]+  Stopped                 sleep 10
$ fg
sleep 10

プロセスID

シェルにおいてコマンド実行するとプロセスIDが割り振られます。

現在、実行中のプロセスを確認するにはpsコマンドを使用します。

jobsコマンドと似ていますが、jobsコマンドはターミナルから実行したジョブが表示されるのに対し、psコマンドでは、現在いるシェルも表示されるなどの違いがあります。

以下の例では、sleep 10 &としてバックグラウンド実行し、それが終了する前にpsコマンドで実行中のジョブを確認しています。

$ sleep 10 &
[1] 39390
$ ps
    PID TTY          TIME CMD
   3217 pts/0    00:00:00 bash
  39390 pts/0    00:00:00 sleep
  39391 pts/0    00:00:00 ps

sleepコマンドの他にもbashpsが実行中であることがわかります。

bashは今いるシェルのことで、psはたった今ジョブを確認するために実行したため、表示されます。

psの確認結果のうちコマンド名が表示されている行の先頭の数値がプロセスIDになります。

前章ではジョブを停止するのにkill %1を使用しましたが、killコマンドはプロセスIDを指定してジョブを終了させることもできます。

$ kill 39390

環境変数

シェルの章で環境変数SHELLのみ紹介しましたが、主な環境変数として以下のようなものがあります。

環境変数意味
HOMEホームディレクトリ
SHELLシェル名
PATHパスを通しているディレクトリ(コロン区切りで複数ディレクトリを指定可)
PWDカレント(現在いる)ディレクトリ

他にも多数あり、printenvコマンドで環境変数と設定値を確認することができます。

環境変数は、今いるシェルから立ち上げた子シェルでも有効なグローバル変数のようなものになります。

環境変数の値を参照するには頭に$を付けて、$PATHのようにします。

$ echo $PATH

新たな環境変数を設定したり、既存の環境変数に値を設定し直すことができます。

環境変数名は、英数字と_(アンダースコア)が使用可能で、先頭の文字に数字は使えません。

環境変数を設定/削除する方法は以下のとおり使用しているシェルによって異なります。

sh(ボーンシェル)系 bash, zsh等

shは最も古くからある言わばシェルの元祖のような存在で、ボーンシェルと呼ばれます。

このshに機能が追加されて使いやすくなったのがbashzshで、これらsh系のシェルは現在最も主流のシェルと言えます。

sh系のシェルで環境変数を設定するには、exportコマンドを使用して以下のように実行します。

$ export PATH="/bin:/usr/bin:/usr/local/bin:$HOME/bin"

上記の=の両側に空白を入れることはできません。

環境変数を削除するには、以下のようにexport -nを使います。

$ export -n ENVVAR

csh(シーシェル)系 tcsh等

cshは構文がC言語に似た感じになっているシェルで、tcshcshの機能追加版です。

csh系のシェルで環境変数を設定するには、setenvコマンドを使用して以下のように実行します。

$ setenv PATH "/bin:/usr/bin:/usr/local/bin:$HOME/bin"

sh系と違って、変数名と設定値の間に=(イコール)は不要で、空白を入れます。

環境変数を削除するには、unsetenvを使用します。

$ unsetenv ENVVAR

シェル変数

シェル変数はシェル内でのみ有効な変数になります。

シェル変数と設定値を確認するにはsetコマンドを使用します。

$ set

シェル変数の値を参照するには環境変数と同様に頭に$を付けて、$numのようにします。

シェル変数名は、環境変数名と同様に英数字と_(アンダースコア)が使用可能で、先頭の文字に数字は使えません。

シェル変数を設定/削除する方法は以下のとおり使用しているシェルによって異なります。

sh(ボーンシェル)系 bash, zsh等

sh系でシェル変数を設定するには、単に変数名と設定値を=(イコール)で区切って設定します。

$ SHVAR="abc"

上記の=の両側に空白を入れることはできません。

シェル変数を削除するには、unsetを使います。(sh/csh共通)

$ unset SHVAR

csh(シーシェル)系 tcsh等

csh系でシェル変数を設定するには、setコマンドを使用して以下のように実行します。

$ set SHVAR = "abc"

上記の=の両側には、空白を入れても入れなくても、どちらでも良いです。

シェル変数を削除するにはunsetを使います。(sh/csh共通)

$ unset SHVAR

環境変数とシェル変数の有効範囲

環境変数とは「今いるシェルから立ち上げた子シェルでも有効なグローバル変数のようなもの」と説明しました。

具体的には、今いるシェルから子シェルを実行した場合、環境変数は引き継がれますが、シェル変数は引き継がれません。

また、子シェルで設定した変数は、環境変数であれシェル変数であれ、親シェルからは参照できません。

Variable scope

クオーテーション”〜”, ‘〜’とエスケープ

文字列を扱う場合、よくダブルクオーテーション”〜”で文字を囲ったり、シングルクオーテーション’〜’で囲っている表現を見かけると思います。

しかし、Linuxにおいてターミナルのコマンドライン上では、基本的にすべて文字列として扱われるので、以下の3つのコマンドはすべて同じくAAAが表示されます。

$ echo "AAA"
AAA
$ echo 'AAA'
AAA
$ echo AAA
AAA

つまり、"AAA"'AAA'も単なるAAAもすべて同じく文字列としてのAAAとして扱われるため、このケースではクオーテーションを付けても付けなくても、どちらでも問題ありません。

常にクオーテーションが不要かというとそうではありません。

クオーテーションが必要なケースとして、例えば空白を含む文字列をコマンド引数に与えたい場合が挙げられます。

AAAに続いて空白3つをはさみBBBが続く文字列をechoで出力したい場合を考えます。

次のようにダブルクオーテーションで囲うと、AAAとBBBの間の空白が3つで意図どおりの結果になります。(シングルクオーテーションでも同じ)

$ echo "AAA   BBB"
AAA   BBB

しかし、以下のようにクオーテーションで囲わずにに実行すると、出力結果の空白は1つになってしまいます。

$ echo AAA   BBB
AAA BBB

コマンドライン上では空白はコマンドや引数間の区切り文字として捉えられ、その空白は1つであっても複数であっても1つの区切りであると認識されます。

つまり、後者の実行方法では、echoコマンドの第1引数にAAA、第2引数にBBBを与えて実行した、ということになり、echoコマンドは複数の引数で与えられた文字列を空白1つで区切って出力するため、結果の空白が1つにされてしまいました。

前者の方はというと、echoコマンドの第1引数に空白3つ入りの文字列を与えて実行した、ということになるので、そのまま空白3つで出力されたという訳です。

このように空白をコマンドや引数の区切りとしてではなく、文字列として扱いたい場合は、ダブルクオーテーションまたはシングルクオーテーションで囲います。

エスケープ

下表の文字は特殊な意味があるため、文字として使用したい場合は、直前に\(バックスラッシュ)を付けて、文字として扱ってくださいという指示を出す必要があります。

この直前に\を付けて文字として扱うことを「エスケープする」といいます。

文字特殊な意味
;コマンドの区切り
&バックグラウンド実行
*ワイルドカード複数文字
?ワイルドカード1文字
!コマンド履歴参照時に使用
$変数の格納値参照
( )(〜)内に;区切りで書かれたコマンドを子シェルを起動して実行
{ }$に続く変数名の区切り
{〜}内に;区切りで書かれたコマンドを今いるシェルで実行、最後のコマンドの後にも;が必要
[ ]testコマンドの略式
>リダイレクト出力
<リダイレクト入力
|パイプ
ダブルクオーテーション、$ ! ` \ 以外を文字として扱う
シングルクオーテーション、’〜’で囲われた文字列をすべて文字として扱う
`バッククオーテーション、`〜`で囲われたコマンドの実行結果を挿入する
\エスケープ、次の1文字を通常の文字として扱う、環境によっては¥と表示される
空白 TABコマンドと引数間の区切り
改行コマンド実行

ダブルクオーテーション”〜”とシングルクオーテーション’〜’の違い

ダブルクオーテーション”〜”に囲まれた文字列内では、$ ! ` \ 以外は普通の文字として扱われます。

変数の値を文字列の中に埋め込みたい場合、以下のようにします。(bashの記述例)

$ age=17
$ echo "I am $age years old."
I am 17 years old.

このように、ダブルクオーテーションの中では$による変数値の埋め込みが可能です。

ここで、上記の17とyearsの間に空白を入れずに表示したい場合を考えます。

以下のように$ageyearsをつなげて書くと、ageyearsという変数を参照するという意味になり、そのような変数は定義していないので、空の値に置き換えられます。

$ age=17
$ echo "I am $ageyears old."
I am  old.

これを解決するために、${変数名}という書き方を使います。

これで変数名がどこまでなのかを明確にでき、期待の動作を実現できます。

$ age=17
$ echo "I am ${age}years old."
I am 17years old.

変数値以外にダブルクオーテーション内では、バッククオーテーションを利用したコマンド実行結果の埋め込みが可能です。

$ echo "Today is `date '+%m/%d'`."
Today is 08/31.

シングルクオーテーション’〜’に囲まれた文字列は、すべて普通の文字として扱われるため、変数値やコマンド実行結果の挿入はできません。

$ age=17
$ echo 'I am $age years old.'
I am $age old.

$ageの部分がそのまま文字列として表示されていますね。

変数の文字列置換

ファイルパスを表現した変数からファイル名を取り出したいなど、変数の値の一部を取り出したいことがよくあり、変数の文字列置換という機能が用意されています。

変数の文字列置換はsh(ボーンシェル)系とcsh(シーシェル)系で異なるので両者を分けて説明します。

sh(ボーンシェル)系 bash, zsh等

sh系(bash, zsh等)には下表の文字列置換機能があり、パターン部分にワイルドカードを含む表現をして、一部を削除したり、置き換えた文字列を取得できます。

sh系と書きましたが、sh(ボーンシェル)には下記文字列置換機能がありません。

変数置換記述意味
${変数名#パターン}先頭から最短マッチ部分を削除
${変数名##パターン}先頭から最長マッチ部分を削除
${変数名%パターン}末尾から最短マッチ部分を削除
${変数名%%パターン}末尾から最長マッチ部分を削除
${変数名/パターン/置換文字列}先頭から見て最初にマッチした部分を置換文字列で置き換え
${変数名//パターン/置換文字列}マッチした部分すべてを置換文字列で置き換え

よく使う使用例をいくつか示します。

変数にパスを格納し、そのパスからファイル名だけを取り出したい場合、以下のようにします。

$ path1=/test/123/foo.c
$ filename=${path1##*/}
$ echo $filename
foo.c

今度はパスからディレクトリ名を取り出す例です。

$ path1=/test/123/foo.c
$ dirname=${path1%/*}
$ echo $dirname
/test/123

拡張子を.cから.oに変更する例です。

$ path1=/test/123/foo.c
$ path2=${path1/.c/.o}
$ echo $path2
/test/123/foo.o

csh(シーシェル)系 tcsh等

csh系(csh, tcsh等)には下表の文字列置換機能がありますが、sh系と違い、パスの編集に特化した機能になっています。

変数置換記述意味
$変数名:r拡張子を削除
$変数名:hディレクトリ部分を取り出す
$変数名:tファイル名を取り出す
$変数名:e拡張子を取り出す

よく使う例をいくつか紹介します。

変数にパスを格納し、そのパスからファイル名だけを取り出したい場合、以下のようにします。

$ set path1 = /abc/123/foo.c
$ set filename = $path1:t
$ echo $filename
foo.c

今度はパスからディレクトリ名を取り出す例です。

$ set path1 = /abc/123/foo.c
$ set dirname = $path1:h
$ echo $dirname
/abc/123

拡張子を.cから.oに変更する例です。

方針としては、拡張子.cを削除して.oを書き足す、ということになります。

$ set path1 = /abc/123/foo.c
$ set path2 = $path1:r.o
$ echo $path2
/abc/123/foo.o

マウスによるコピー&ペースト

Windowsではマウスで文字列を選択してCtrl+Cでコピー、Ctrl+Vで貼り付け、MacではCommand+Cでコピー、Command+Vで貼り付けを行いますが、Linuxではマウスドラッグで範囲指定しただけで同時にコピーされます。

貼り付ける際は、マウスの中央クリック(ホイールを押し込む)となります。

上記を基本的に使用しますが、最近のLinuxでは、マウスの右クリック→Copy(コピー)、マウスの右クリック→Paste(貼り付け)でもコピー&ペーストができるようになっています。

まとめ

ターミナルの基本的な操作方法とシェルについての基礎的な内容を紹介しました。

このページの内容は、Linuxを使う人にとってはどれも当たり前の内容ですが、文字にしてみると意外と分量が多いですね。

1回読んだだけでは、なかなか身に付かないと思いますので、普段からターミナルを触っていろいろ試していただき、こんなときどうするんだっけ?と思ったときに改めて見返していただけると定着していくと思います。

最後まで読んでいただきありがとうございます。

文献紹介

新しいLinuxの教科書

Linuxの基本的な使い方からシェルスクリプトを使ったプログラミング、gitによるバージョン管理など、エンジニアが知っておくべき基本的な知識について解説してくれています。

参考文献

タイトルとURLをコピーしました