本記事は「ものづくりのための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/…/ファイル名(またはディレクトリ名)
単に/とすると、最上位のディレクトリのことを表し、ルートディレクトリと呼ばれます。
上記で説明したのは、パスの先頭が/となる絶対パス表現となります。
絶対パスはフルパスと呼ばれることがあります。
これに対し、先頭が/から始まらない相対パス表現という方法もあります。
例えば以下の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.txt
、test2.txt
、test_123.sh
という3つのファイルがある場合、これらのファイル名に合致するため、以下のコマンドを実行したのと同じことになります。
$ grep -i abc test1.txt test2.txt test_123.sh
*を前につけて、*test
として前半部分を柔軟にしたり、*test*
として一部にtest
が入るファイルを対象にしたりできます。
ワイルドカードには*の他にもう1つ?(クエスチョンマーク)があり、こちらは任意の1文字を表します。
例えば、上記の場合と同様にカレントディレクトリにtest1.txt
、test2.txt
、test_123.sh
という3つのファイルがある場合に以下のコマンドを実行するとどうなるか見ていきます。
$ grep -i abc test?.txt
この場合、test?.txt
は、test1.txt
とtest2.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文字 |
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.txt
とfileB.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 |
カーソルを一番左に移動 | Home | Ctrl+A |
カーソルを一番右に移動 | End | Ctrl+E |
カーソルの左の文字を削除 | BackSpace | Ctrl+H |
カーソル上の文字を削除 | Delete | Ctrl+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> |
標準エラー出力 | 2 | 2> |
例えば、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
コマンドを実行しています。
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
コマンドを使用します。
以下の例では、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
コマンドの他にもbash
とps
が実行中であることがわかります。
bash
は今いるシェルのことで、ps
はたった今ジョブを確認するために実行したため、表示されます。
ps
の確認結果のうちコマンド名が表示されている行の先頭の数値がプロセスIDになります。
前章ではジョブを停止するのにkill %1
を使用しましたが、kill
コマンドはプロセスIDを指定してジョブを終了させることもできます。
$ kill 39390
環境変数
シェルの章で環境変数SHELLのみ紹介しましたが、主な環境変数として以下のようなものがあります。
環境変数 | 意味 |
---|---|
HOME | ホームディレクトリ |
SHELL | シェル名 |
PATH | パスを通しているディレクトリ(コロン区切りで複数ディレクトリを指定可) |
PWD | カレント(現在いる)ディレクトリ |
他にも多数あり、printenv
コマンドで環境変数と設定値を確認することができます。
環境変数は、今いるシェルから立ち上げた子シェルでも有効なグローバル変数のようなものになります。
環境変数の値を参照するには頭に$
を付けて、$PATH
のようにします。
$ echo $PATH
新たな環境変数を設定したり、既存の環境変数に値を設定し直すことができます。
環境変数名は、英数字と_(アンダースコア)が使用可能で、先頭の文字に数字は使えません。
環境変数を設定/削除する方法は以下のとおり使用しているシェルによって異なります。
sh(ボーンシェル)系 bash, zsh等
sh
は最も古くからある言わばシェルの元祖のような存在で、ボーンシェルと呼ばれます。
このsh
に機能が追加されて使いやすくなったのがbash
やzsh
で、これらsh
系のシェルは現在最も主流のシェルと言えます。
sh
系のシェルで環境変数を設定するには、export
コマンドを使用して以下のように実行します。
$ export PATH="/bin:/usr/bin:/usr/local/bin:$HOME/bin"
上記の=の両側に空白を入れることはできません。
環境変数を削除するには、以下のようにexport -n
を使います。
$ export -n ENVVAR
csh(シーシェル)系 tcsh等
csh
は構文がC言語に似た感じになっているシェルで、tcsh
はcsh
の機能追加版です。
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
環境変数とシェル変数の有効範囲
環境変数とは「今いるシェルから立ち上げた子シェルでも有効なグローバル変数のようなもの」と説明しました。
具体的には、今いるシェルから子シェルを実行した場合、環境変数は引き継がれますが、シェル変数は引き継がれません。
また、子シェルで設定した変数は、環境変数であれシェル変数であれ、親シェルからは参照できません。
クオーテーション”〜”, ‘〜’とエスケープ
文字列を扱う場合、よくダブルクオーテーション”〜”で文字を囲ったり、シングルクオーテーション’〜’で囲っている表現を見かけると思います。
しかし、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の間に空白を入れずに表示したい場合を考えます。
以下のように$age
とyears
をつなげて書くと、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等)には下表の文字列置換機能があり、パターン部分にワイルドカードを含む表現をして、一部を削除したり、置き換えた文字列を取得できます。
変数置換記述 | 意味 |
---|---|
${変数名#パターン} | 先頭から最短マッチ部分を削除 |
${変数名##パターン} | 先頭から最長マッチ部分を削除 |
${変数名%パターン} | 末尾から最短マッチ部分を削除 |
${変数名%%パターン} | 末尾から最長マッチ部分を削除 |
${変数名/パターン/置換文字列} | 先頭から見て最初にマッチした部分を置換文字列で置き換え |
${変数名//パターン/置換文字列} | マッチした部分すべてを置換文字列で置き換え |
よく使う使用例をいくつか示します。
変数にパスを格納し、そのパスからファイル名だけを取り出したい場合、以下のようにします。
$ 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の基本的な使い方からシェルスクリプトを使ったプログラミング、git
によるバージョン管理など、エンジニアが知っておくべき基本的な知識について解説してくれています。
参考文献
- シェルや正規表現のエスケープについてのメモ(https://yamamotoh.hatenablog.com/entry/20170805/1501909860)
- Bashにおける括弧類の意味(https://qiita.com/yohm/items/3527d517768402efbcb6)
- ものづくりのためのLinux講座【基本コマンド】(https://take6shin-tech-diary.com/linux_command/)