Shellスクリプト基礎知識(全13記事+2)
├─【Shellの基礎知識】Shellスクリプト入門|初心者が押さえる基本
├─【Shellの基礎知識】変数と特殊変数の使い方|初心者向け解説
├─【Shellの基礎知識】Shell演算子の完全ガイド|基礎から応用まで
├─【Shellの基礎知識】条件分岐『if』『case』の使い方を解説
├─【Shellの基礎知識】ループ処理の基本|効率化と応用例を解説
├─【Shellの基礎知識】文字列置換の基本と応用|初心者向け解説
├─【Shellの基礎知識】複数行テキスト出力を簡単に!ヒアドキュメント活用法
├─【Shellの基礎知識】関数の基本と応用|書式と戻り値を解説
├─【Shellの基礎知識】組み込みコマンドの活用法|最適化テクニック
├─【Shellの基礎知識】クォートとコマンド置換の違いと使い分け
└─【Shellの基礎知識】リダイレクトの基本|標準入出力とエラー出力
└─【Shellの基礎知識】中級者向けShellスクリプト|実用的な書き方とコツ
└─【Shellの基礎知識】中級者向けShell活用術|10の応用Tipsを紹介
(補足)【Shellの基礎知識】シェルスクリプトの設計書とは?必要な項目や書き方等を解説!
(補足)【Shellの基礎知識】初心者向け!便利なShellコマンド集【カテゴリ別】
テスト中など、名前に唯一性のあるファイルを複数個保持したいケースがあります。そんな時、自動でタイムスタンプをつけたり、ファイル名に変数を使えれば便利ですが、これには各種クォートによる装飾が必要です。
ここではクォートの機能と使い方を見ていきます。
Shellスクリプトにおけるクォートとコマンド置換の重要性
Shellスクリプトは、シンプルで強力なツールですが、細かいルールを理解していないと簡単にミスを招いてしまいます。その中でも「クォート」と「コマンド置換」は、初心者が最初につまずきやすい重要な概念です。これらを正しく理解し、使い分けることができれば、スクリプトの信頼性と効率性を大きく向上させることができます。
Shellスクリプト初心者が理解すべき基本概念
クォートとコマンド置換は、それぞれ以下のような役割を持っています。
理解すべき基本概念
- クォート
テキストや変数の扱いを制御し、意図しない動作を防ぐ。
例: 文字列をそのまま扱いたい場合はシングルクォート、変数展開を含む場合はダブルクォートを使用。 - コマンド置換
コマンドの出力結果を別のコマンドや変数に利用する仕組み。
例: $(command) を使って、コマンドの出力結果を動的に処理。
これらの基本を押さえることで、スクリプトの挙動を予測可能にし、デバッグも容易になります。
ミスを防ぐために知っておきたいポイント
ミスを起こさないポイント
- クォートの使い方を誤ると予期しない動作に繋がる
例: ダブルクォートを使うべき場面でシングルクォートを使用すると、変数展開が行われず意図した結果にならない。 - コマンド置換の古い形式と新しい形式を混在させない
古い形式(バッククォート)は、可読性が低くエラーを引き起こしやすいため、新しい形式($(command))に統一することが推奨されます。 - 明確な使い分けを意識する
目的や状況に応じて適切な方法を選ぶことで、スクリプト全体が簡潔で管理しやすくなります。
クォートとコマンド置換を正しく理解することは、効率的なShellスクリプト作成の第一歩です。この記事では、それぞれの仕組みと使い分け方を具体例とともに詳しく解説していきます。
クォート(Quotation)の基礎知識
Shellスクリプトにおける「クォート(Quotation)」は、文字列や特殊な記号をどのように扱うかを決定づける重要な機能です。クォートの使い方を正しく理解することで、スクリプトの動作を予測しやすくなり、思わぬエラーを防ぐことができます。このセクションでは、クォートの種類と役割、さらにその具体的な影響について解説します。
クォートの種類と役割
文章においてはいわゆる引用符ですが、シェルスクリプトにおいては、囲まれた内容について特別な処理を行います。
クォートは以下の3つに分かれます。
3つのシェルのクォート
- シングルクォート 「’ ’」:
囲んだ内容をそのままの文字列として出力。 - ダブルクォート 「””」:
囲んだ内容に変数がある場合は中身を展開し、文字列として出力 - バッククォート 「``」:
囲んだ内容のコマンドを、同じ行の他のコマンドより先に解釈して実行する
バッククォートに関しては、前半2つのクォートと用途がやや異なり、コマンドに用います。
それぞれ見ていきましょう。
シングルクォート「’」
シングルクォートは、文字列をそのまま扱いたいときに使用します。
このクォート内では、特殊文字や変数展開が一切無効化され、文字列がリテラルとして解釈されます。
シングルクォートで囲まれた中身はすべてそのままの文字列として出力されます。これがシェルのクォーテーションの中では一番強力なものになります。
内部に変数が含まれている場合でも、すべてエスケープされて中身は展開されません。
特徴と使用シーン
- 特殊文字(例: $, *, \ など)をそのまま文字列として扱いたい場合に使用。
- 変数やコマンドを展開せず、固定値として処理したい場合に適しています。
1 2 3 4 5 | [root@CentOS7 ~]# site_name="Beエンジニア" [root@CentOS7 ~]# echo ${site_name} Beエンジニア [root@CentOS7 ~]# echo '${site_name}' 👈 変数として展開できない ${site_name} |
シングルクォートでもエスケープ出来ないのは、このシングルクォートだけになります。
シングルクォート「’」とバッククォート「`」は取り違えないように注意しましょう。見た目は似ていますが機能は全く異なります。
なお、シングルクォートの中にシングルクォートがある場合、エスケープされて通常表示されません。なんのこっちゃ?・・
ポイント
- $ を含む変数を展開。
- 特殊文字の一部(例: \n, \t)をエスケープ処理。
- 特殊文字の影響を部分的に無効化。
# シングルクォートで囲まれたシングルクォート
echo 'It's a single quote'
つまり、上記の例のような「’(シングルクォート)」で囲まれた「’(シングルクォート)」は、文字列として認識できないと言う事です。
1 2 | [root@CentOS7 ~]# echo 'It's a single quote' > 👈 クォートのミスマッチ(数が合わない) |
シングルクォートを含む文字列の記述方法
シングルクォートをエスケープするには、シングルクォート自体をエスケープする方法が存在しないため、工夫が必要です。代わりに、以下のように シングルクォートを閉じて再び開き、間にエスケープしない文字列を挿入 する方法を取ります。
シングルクォートで囲む文字列内でシングルクォートを使用する場合、文字列を分割して適切に組み立てます。
シングルクォートを閉じて開き直す
echo 'It'"'"'s a single quote'
- 'It' → 最初の文字列部分。
- '"'" → シングルクォートを閉じ、ダブルクォート内にシングルクォートを挿入。
- 's a single quote' → 残りの文字列部分。
1 2 | [root@job01 -]# echo 'It'"'"'s a single quote' It's a single quote |
この方法では、ダブルクォート内でシングルクォートをそのまま使用可能です。
シングルクォート内でシングルクォートを使いたい場合、'"'" の方法が必要になりますが、可読性を考慮してダブルクォートを利用できる場面ではそちらを使う方が簡潔です。
ダブルクォート「”」
ダブルクォートは、ほとんどの特殊文字の意味をエスケープし、文字として扱います。
「”(ダブルクォート)」の場合は、シングルクォートと異なり、内部に変数が存在する場合はそれを展開して文字列を出力します。
1 2 3 4 5 | [root@CentOS7 ~]# site_name="Beエンジニア" [root@CentOS7 ~]# echo ${site_name} Beエンジニア [root@CentOS7 ~]# echo "${site_name}" 👈 変数として展開可能 Beエンジニア |
「‘(バツククォート)」、「\(バックスラッシュ)」等の特殊文字はダブルクォートで囲んでも、エスケープすることは出来ません。エスケープが必要な場合は「’(シングルクォート)」で囲みます。例)「echo ' / '」
- $ を含む変数を展開。
- 特殊文字の一部(例: \n, \t)をエスケープ処理。
- 特殊文字の影響を部分的に無効化。
バッククォート (``)
バッククォートは、コマンド置換として使用される古い形式のクォートです。
現在では新しい形式 $(command) が推奨されており、バッククォートはレガシーな方法と見なされています。
レガシーな利用方法と注意点
- コマンドの出力を取得して利用。
- ネストが必要な場合に可読性が低下しやすい。
output=`date`
echo "Current date: $output" # 出力: Current date: [現在の日付]
新しい『$()』形式に比べてネスト構造が複雑になるため、エラーを引き起こしやすい点に注意してください。
クォートが影響を与える具体例
文字列リテラル
クォートの使い方によって文字列の扱い方が異なります。
text='Hello, World!'
echo $text # 出力: Hello, World!
echo "$text" # 出力: Hello, World!
echo '$text' # 出力: $text
シングルクォートでは変数展開が無効化され、リテラルとして解釈されることがわかります。
メタキャラクターとエスケープ処理
クォートを使用することで、メタキャラクター(例: *, ?, [ ] など)の影響を制御できます。
echo * # 現在のディレクトリ内のファイル一覧を出力
echo '*' # 出力: *
echo "The file is: *" # 出力: The file is: *
また、ダブルクォート内ではエスケープ処理を活用して、特定の文字を無効化できます。
echo "This is a \"quoted\" word." # 出力: This is a "quoted" word.
クォートの正しい使い方を理解することで、Shellスクリプトの挙動を制御し、効率的にコードを書くことが可能になります。次のセクションでは「コマンド置換」について詳しく解説します。
バックスラッシュ(\)
クォートとは異なりますが、シングルクォートの項目でも説明したように、シングルクォート内のシングルクォートは表示されないため、「Test 'is' done」のような文字列を出力する時には、工夫が必要です。
このような時にはバックスラッシュ(\)を使い、シングルクォート直前につければ出力させることが出来ます。しかし以下の例のように少し複雑に書くことになります。
$ echo 'Test '\''is'\'' done'
「\(バックスラッシュ)」は次の特殊文字をエスケープして、普通の文字として扱います。
1 2 | [root@CentOS7 ~]# echo 'Test '\''is'\'' done' Test 'is' done |
シェルスクリプトでは、特にこの「\(バックスラッシュ)」によるエスケープ処理は、多用することが多いので頭の片隅に置いておきましょう。
コマンド置換(Command Substitution)の基本
コマンド置換(Command Substitution)とは、ある行の他のコマンドよりも先行して別のコマンドを実行したいときに行う処理で、先述したバッククォートか、$(command)の形でコマンドを囲んで記述することで実現する事が出来ます。
コマンド置換とは?
コマンド置換は、Shellスクリプト内で外部コマンドを実行し、その出力を取得してスクリプト内で活用する仕組みです。
例えば、サーバー名を末尾に持つファイルを作りたい時には以下のようなコマンドを実行します。
使用目的と仕組み
- 目的: コマンドの出力結果を動的に取得し、スクリプト内で利用すること。
- 例: ファイル名の動的生成、現在の日付の取得、システム情報の取得など。
- 仕組み: コマンドを特定の構文で囲むことで、その結果を他の処理に渡します。
$ touch "file_`uname -n`"
または
$ touch "file_$(uname -n)"
上記コマンドを実行した場合、作られるファイル名はいずれも「file_<ホスト名>」と言うファイルが作成されます。それぞれの記述の違いを見ていきましょう。
バッククォート「`」によるコマンド置換
バッククォート(`command`
)を使用する形式は、コマンド置換の元祖ともいえる構文です。先の例で出したように、バッククォートでコマンドを囲むことで記述します。
$ DATE=`date`
$ echo $DATE
特徴
- コマンドの出力結果を取得し、変数や別の処理に利用可能。
- シンプルだが、ネストしたコマンド置換には不向き。
1 2 3 | [root@CentOS7 ~]# DATE=`date` [root@CentOS7 ~]# echo ${DATE} 2020年 4月 19日 日曜日 16:27:45 JST |
バッククォートはネストする事が可能ですが、2つ以上の場合はその分だけバックスラッシュを入れ子にしたエスケープが必要です。
$ echo "aaa `echo bbb \`echo ccc\``"
1 2 | [root@CentOS7 ~]# echo "aaa `echo bbb \`echo ccc\``" aaa bbb ccc |
もし複数回ネストしたい場合は、次に示す$()での記述が簡潔で良いでしょう。
バッククォートで囲む形式は古い形式であり、現在では新しい『$()』形式が推奨されます。
「$()」によるコマンド置換
バッククォートの場合と同様に、コマンドを"$("と")"の記号で囲むことで記述します。ネストしたい場合はエスケープは用いず、単純に$()を内側に書けば実現できます。
いわば「$( )」は、バッククォートの代替機能となります。「上位互換」と言っても過言ではありません。
コマンドの書式
$( コマンド )
# $()によるコマンド置換
$ echo "aaa $(echo bbb)"
# $()によるネストコマンド置換
$ echo "aaa $(echo bbb $(echo ccc))"
メリット
- コードの保守性が向上。
- ネストしたコマンド置換も直感的に記述可能。
1 2 3 4 | [root@CentOS7 ~]# echo "aaa $(echo bbb)" aaa bbb [root@CentOS7 ~]# echo "aaa $(echo bbb $(echo ccc))" aaa bbb ccc |
クォートやコマンド置換は組み合わせて使用可能なため、状況に応じて簡潔な記述で意図を達成するよう心掛けましょう。
「`(バッククォート)」は古い形式であり、「’(シングルクォート)」と非常に紛らわしいため、可能なら「$( )」を積極的に使用していきましょう。なお「‘(バッククォート)」と「$( )」の機能に差はありません。
コマンド置換の具体例
コマンド置換は、さまざまな場面で使用されます。ここでは、実用的な例をいくつか紹介します。
実用例:変数への値の代入
コマンドの出力結果を変数に代入し、その値を再利用します。
# 現在の日付を取得して変数に代入
current_date=$(date)
echo "The script ran on: $current_date"
実用例:ループや条件分岐での使用
コマンド置換を使用してループや条件分岐を動的に制御します。
ディレクトリ内のファイル一覧をループで処理
for file in $(ls /path/to/directory); do
echo "Processing file: $file"
done
条件分岐でコマンドの出力を判定
if [ $(whoami) = "root" ]; then
echo "You are running this script as root."
else
echo "You are not root."
fi
コマンド置換を正しく理解して使いこなすことで、Shellスクリプトの柔軟性と効率性を大幅に向上させることができます。バッククォート形式と新しい形式の違いを理解し、現代的な形式を積極的に活用することをお勧めします。次のセクションでは、クォートとコマンド置換の使い分けについて解説します。
クォートとコマンド置換の使い分け方
Shellスクリプトで「クォート」と「コマンド置換」を適切に使い分けることは、スクリプトの正確性や安全性を保つ上で非常に重要です。このセクションでは、実践的な判断基準と、よくある誤解やトラブルへの対処法を解説します。
実践的な判断基準
クォートとコマンド置換をどのように組み合わせるかを決定するためには、以下の基準を意識することが大切です。
文字列処理とコマンド置換の組み合わせ
コマンド置換で得た結果を文字列として扱う場合、適切なクォートを使用することで、意図しない動作を防ぐことができます。
ポイント
- シングルクォート (') は、文字列をそのまま扱いたい場合に使用。
- ダブルクォート (") は、変数展開やコマンド置換を有効にする場合に使用。
#コマンド置換結果を安全に使用
current_date=$(date)
echo "Today is: $current_date" # ダブルクォートで変数展開を有効に
クォートなしでコマンド置換を使用すると、空白文字が分割されてしまう可能性があります。
files=$(ls) # 注意: 空白を含むファイル名が分割される
echo $files # 出力が崩れる可能性
echo "$files" # 安全に文字列として扱う
安全なスクリプトを書くためのコツ
安全なスクリプトを書くためには、次のようなコツを意識してください。
常にクォートを使用する
意識するポイント
- 常にクォートを使用する
コマンド置換の結果を変数や引数で使用する際は、必ずダブルクォートで囲みます。output=$(some_command)
echo "$output" # 安全
- 新しい形式のコマンド置換を使用
古い形式(バッククォート)は可読性が低くエラーを招きやすいため、$(command) を使用しましょう。 - デバッグを活用
set -x をスクリプトの冒頭に追加すると、実行されるコマンドを確認できます。
よくある誤解とトラブルシューティング
Shellスクリプトを記述する際、クォートやコマンド置換の使い方を誤解していると、スクリプトが意図したとおりに動作しないことがあります。特に、初心者が直面しやすい誤解やトラブルの多くは、クォートの種類やコマンド置換の結果の扱いに起因します。
このセクションでは、よくある誤解とその原因、そして実践的なトラブルシューティング方法について解説します。これらを理解することで、スクリプトのデバッグが容易になり、安定した動作を実現できます。
クォートの誤用によるエラー
クォートを適切に使用しないと、予期しないエラーが発生することがあります。
例1: クォートなしでの変数展開
files=$(ls)
for file in $files; do # 空白で分割される
echo $file
done
修正方法:
for file in "$files"; do # ダブルクォートで安全に処理
echo "$file"
done
例2: シングルクォート内で変数展開を期待する
name="User"
echo 'Hello, $name!' # 文字列そのまま出力 (展開しない)
修正方法:
echo "Hello, $name!" # 変数展開が有効
コマンド置換での予期せぬ動作
コマンド置換の使用中に思わぬ結果が出るケースもよくあります。
例1: コマンド置換の空白文字処理
files=$(ls)
echo $files # 空白で分割されたファイル名が崩れる
修正方法:
echo "$files" # 正しい出力
例2: コマンド置換の失敗を確認しない
output=$(some_command)
echo "Command output: $output" # コマンド失敗時でも空の結果
修正方法:
output=$(some_command)
if [ $? -ne 0 ]; then
echo "Command failed"
else
echo "Command output: $output"
fi
Shellスクリプトを記述する際、クォートやコマンド置換の使い方を誤解していると、スクリプトが意図したとおりに動作しないことがあります。特に、初心者が直面しやすい誤解やトラブルの多くは、クォートの種類やコマンド置換の結果の扱いに起因します。
このセクションでは、よくある誤解とその原因、そして実践的なトラブルシューティング方法について解説します。これらを理解することで、スクリプトのデバッグが容易になり、安定した動作を実現できます。
クォートとコマンド置換を活用したスクリプトの最適化
Shellスクリプトを効率的かつ安全に記述するには、クォートとコマンド置換の活用が欠かせません。適切に使うことで、スクリプトの可読性が向上し、エラーのリスクを大幅に減らすことができます。このセクションでは、読みやすいスクリプトを書くためのヒントと、応用的なテンプレート生成の例を紹介します。
より読みやすいスクリプトを書くためのヒント
読みやすいスクリプトは、メンテナンス性が高く、エラーを防ぎやすいのが特徴です。このセクションでは、クォートやコマンド置換を活用しながら、簡潔で直感的なスクリプトを書くための具体的なヒントを紹介します。
- クォートを適切に使う
- 変数やコマンド置換の結果を扱う際は、必ずダブルクォートで囲む。
- 明確に固定値である場合はシングルクォートを使用。
# 正しいクォートの使い方
name="User"
echo "Hello, $name" # ダブルクォートで変数展開
echo 'This is a fixed string' # シングルクォートで固定値
- コマンド置換は新しい形式を使用
- 新しい形式 $(command) を使うことで、可読性と保守性を向上。
files=$(ls -l)
echo "$files"
- コメントを活用する
- スクリプトに意図を記述して、他者や未来の自分に優しいコードを書く。
ユーザー名を取得して表示
username=$(whoami)
echo "Current user: $username"
- 構造をシンプルに保つ
- 不要なネストや冗長なコマンドを避け、簡潔なスクリプトを目指す。
実用例:Shellスクリプトでのテンプレート生成
テンプレート生成は、動的な値を埋め込んだり、同じ形式のファイルを効率よく作成したりする際に非常に有用です。
スクリプト例:テンプレート生成
以下は、テンプレートファイルに動的な値を埋め込む例です。
テンプレートファイル (template.txt):
Hello, {{NAME}}!
Welcome to {{PLACE}}.
Today is {{DATE}}.
スクリプト (generate_template.sh):
#!/bin/bash
# テンプレートの動的値
name="Alice"
place="Wonderland"
date=$(date '+%Y-%m-%d')
# テンプレートファイルを読み込み、値を置換
sed "s/{{NAME}}/$name/g; s/{{PLACE}}/$place/g; s/{{DATE}}/$date/g" template.txt > output.txt
echo "Generated template:"
cat output.txt
ポイント:
ポイント
- コマンド置換で日付など動的な値を取得。
- sed コマンドでテンプレートのプレースホルダーを置換。簡潔でわかりやすい構造にまとめる。
よくある質問(FAQ)
シングルクォートとダブルクォートの違いは?
シングルクォート( ' )
- 文字列をそのままリテラルとして扱う。
- 特殊文字や変数展開は無効。
echo 'This is $HOME' # 出力: This is $HOME
ダブルクォート(
- 変数展開やエスケープシーケンスを有効化。
- 柔軟性が高く、使用頻度も高い。
echo "This is $HOME" # 出力: This is /home/username
コマンド置換の新旧形式を混在させてもいいの?
推奨されません。
古い形式(バッククォート)は、ネストが複雑になると可読性が低下し、エラーを招きやすいため、可能な限り新しい形式 $(command) に統一することが望ましいです。
# 推奨されない
output=`echo $(date)`
# 推奨
output=$(echo $(date))
クォートを使うとパフォーマンスに影響はある?
クォート自体は、パフォーマンスへの直接的な影響はほとんどありません。ただし、以下の点には注意が必要です。
- エラー防止による効率化:
- クォートの適切な使用は、予期しないエラーを防ぎ、スクリプトのデバッグ時間を削減します。
- 大規模データの処理:
- クォートがない場合、空白や特殊文字を含むデータ処理でエラーが発生し、スクリプトの再実行が必要になることがあります。
クォートとコマンド置換を正しく使いこなすことで、効率的で堅牢なスクリプトを作成することが可能です。これらの応用方法やFAQを参考に、さらに洗練されたスクリプトを目指してみてください!
この記事を読んだら、次は 「【Shellの基礎知識】リダイレクトの基本|標準入出力とエラー出力」を読むのがおすすめです!