Linux Professional Institute Learning Logo.
main contentにスキップ
  • ホーム
    • 全てのリソース
    • LPI学習教材
    • コントリビューターになる
    • Publishing Partners
    • Publishing Partnerになる
    • About
    • FAQ
    • コントリビューター
    • Roadmap
    • 連絡先
  • LPI.org
3.3 レッスン 2
課題 1: Linuxコミュニティとオープンソースのキャリア
1.1 ポピュラーなOSとLinuxの発展
  • 1.1 レッスン 1
1.2 主なオープンソースのアプリケーション
  • 1.2 レッスン 1
1.3 オープンソースソフトウエアとライセンス
  • 1.3 レッスン 1
1.4 ICTスキルとLinuxでの作業
  • 1.4 レッスン 1
課題 2: Linuxシステムで自分の手法を見つける
2.1 コマンドラインの基本
  • 2.1 レッスン 1
  • 2.1 レッスン 2
2.2 コマンドラインのヘルプ機能の利用
  • 2.2 レッスン 1
2.3 ディレクトリの利用とファイルの一覧
  • 2.3 レッスン 1
  • 2.3 レッスン 2
2.4 ファイルの作成、移動と削除
  • 2.4 レッスン 1
課題 3: コマンドラインの力
3.1 コマンドラインでのファイル圧縮
  • 3.1 レッスン 1
3.2 ファイルの検索と展開
  • 3.2 レッスン 1
  • 3.2 レッスン 2
3.3 コマンドをスクリプトにする
  • 3.3 レッスン 1
  • 3.3 レッスン 2
課題 4: Linuxオペレーティングシステム
4.1 オペレーティングシステムの選択
  • 4.1 レッスン 1
4.2 コンピュータハードウエアの理解
  • 4.2 レッスン 1
4.3 データの保管場所
  • 4.3 レッスン 1
  • 4.3 レッスン 2
4.4 ネットワーク上のコンピュータ
  • 4.4 レッスン 1
課題 5: セキュリティとファイルパーミッション
5.1 セキュリティの基本と、ユーザタイプの確認
  • 5.1 レッスン 1
5.2 ユーザとグループの作成
  • 5.2 レッスン 1
5.3 ファイルのパーミッションと所有権の管理
  • 5.3 レッスン 1
5.4 特別なディレクトリとファイル
  • 5.4 レッスン 1
How to get certified
  1. 課題 3: コマンドラインの力
  2. 3.3 コマンドをスクリプトにする
  3. 3.3 レッスン 2

3.3 レッスン 2

Certificate:

Linux Essentials

Version:

1.6

Topic:

3 コマンドラインの力

Objective:

3.3 コマンドをスクリプトにする

Lesson:

2 of 2

はじめに

このセクションでは、以下の例を使って、Bashスクリプトを見ていきます:

#!/bin/bash

# A simple script to greet a single user.

if [ $# -eq 1 ]
then
  username=$1

  echo "Hello $username!"
else
  echo "Please enter only one argument."
fi
echo "Number of arguments: $#."
  • スクリプトは、インタープリタのパスを示す シェバン で始めます。

  • スクリプトには、その使い方を説明するコメントを入れておきます。

  • 例示するスクリプトは、起動時に渡される1つの 引数 を使います。

  • このスクリプトには、組み込み変数 $# の状態を判定する if文 を含んでいます。この変数には、引数の数がセットされます。

  • スクリプトに渡された引数の数が1であれば、最初の引数の値を新しい変数 username にセットし、スクリプトはあいさつを表示します。その他の場合には、エラーメッセージを表示します。

  • 最後に、スクリプトは引数の数を表示します。これはデバッグに役立ちます。

このスクリプトは、Bashスクリプトの他の機能を説明するためにも良いスタート点になります。

終了コード

このスクリプトには、2つの状態があることに気づくでしょう: "Hello <user>!" と表示するか、エラーメッセージを表示するか、です。ほとんどのユーティリティも、同様の構成です。お馴染みの cat を例に取り上げます。

cat の実行に成功した場合と、失敗した場合を比べてみましょう。ここで取り上げるスクリプトは、new_script.sh です。

$ cat -n new_script.sh

     1	#!/bin/bash
     2
     3	# A simple script to greet a single user.
     4
     5	if [ $# -eq 1 ]
     6	then
     7	  username=$1
     8
     9	  echo "Hello $username!"
    10	else
    11	  echo "Please enter only one argument."
    12	fi
    13	echo "Number of arguments: $#."

cat コマンドの実行は成功して、-n フラグによって行番号も出力されました。行番号はスクリプトのデバッグ時に役立ちますが、これはスクリプトの一部では ない ことに注意して下さい。

ここで、新登場の組み込み変数 $? の値を確認します。出力に着目しましょう:

$ echo $?
0

次に、cat が失敗する場合を見ていきます。まずエラーメッセージを確認して、$? 変数をチェックします。

$ cat -n dummyfile.sh
cat: dummyfile.sh: No such file or directory
$ echo $?
1

この動作について説明します: cat を実行する度に 終了コード が返されます。終了コードは、コマンドが成功したのか、何かのエラーが発生したのかを示します。終了コード ゼロ はコマンドが成功裏に完了したことを意味します。利用する機会の多いLinuxコマンドのほとんどが、このように動作します。ゼロ以外の終了コードは、何らかのエラーを示します。$? には、直前に実行されたコマンド の終了コードがストアされます。

ユーザーが終了コードを目にすることは通常ありませんが、スクリプトを書く場合には非常に役立ちます。例えば、ファイルをリモートのネットワークドライブにコピーするスクリプトを考えてみましょう。コピーに失敗する原因はたくさんあります: 例えば、ローカルマシンがネットワークに接続されていなかったり、リモートドライブが満杯であったり、などなど。コピーユーティリティの終了コードをチェックすることで、スクリプト実行中に問題の発生をユーザーに警告することができます。

終了コードを実装しておくことはとても良い習慣ですから、ここで実行しておきましょう。スクリプトには、成功と失敗の2つのパスがあります。成功を示すのにゼロを、失敗を示すのに1を使います。

     1	#!/bin/bash
     2
     3	# A simple script to greet a single user.
     4
     5	if [ $# -eq 1 ]
     6	then
     7	  username=$1
     8
     9	  echo "Hello $username!"
    10	  exit 0
    11	else
    12	  echo "Please enter only one argument."
    13	  exit 1
    14	fi
    15	echo "Number of arguments: $#."
$ ./new_script.sh Carol
Hello Carol!
$ echo $?
0

15行目の echo コマンドが、完全に無視されることに注意して下さい。exit を使用するとスクリプトはすぐに終了してしまうので、決してこの行に至ることがありません。

たくさんの引数を扱う

これまでのところ、スクリプトは1つの引数しか扱うことができませんでした。1つ以外の引数を指定すると、エラーになります。このスクリプトを、より汎用性の高いものにする方法を見ていきます。

直感的には、$2 や $3 など、もっとたくさんの位置変数を使えばよいと考えるかもしれません。残念ながら、ユーザーが幾つの引数を使うかを予測することはできません。この問題を解決するためには、別の組み込み変数を導入することが有用です。

スクリプトのロジックを変更しましょう。引数がゼロ個の時はエラーとしますが、それ以外の個数の引数では成功するようにします。この新しいスクリプトを friendly2.sh と呼びます。

     1	#!/bin/bash
     2
     3	# a friendly script to greet users
     4
     5	if [ $# -eq 0 ]
     6	then
     7	  echo "Please enter at least one user to greet."
     8	  exit 1
     9	else
    10	  echo "Hello $@!"
    11	  exit 0
    12	fi
$ ./friendly2.sh Carol Dave Henry
Hello Carol Dave Henry!

スクリプトに渡されたすべての引数を格納する組み込み変数が2つあります: $@ と $* です。ほとんどの場合、どちらも同じように動作します。Bash は引数を 解析 して、空白を見つける度にそれぞれを区切ります。実際には、$@ の内容は以下のようになります。

0

1

2

Carol

Dave

Henry

他のプログラミング言語に慣れているならば、この種の変数が 配列 であると分かるでしょう。Bashでは、以下に示す arraytest の中の FILES 変数のように、単純に要素を空白で区切って配列を作ることができます。

FILES="/usr/sbin/accept /usr/sbin/pwck/ usr/sbin/chroot"

配列は、複数の項目のリストです。まだ項目それぞれを扱う方法を紹介していないので、今のところはあまり役に立ちません。

Forループ

先に述べた arraytest の例を見ていきましょう。この例では、FILES という配列を指定しています。この変数をほどいて、個々の値に順にアクセスする方法が必要です。これを行うには、すべてのプログラミング言語にある Forループ と呼ばれる構造を用います。ここでは2つの変数を使います: ひとつは範囲で、もう一つは作業中の個別の値です。スクリプト全体を示します:

#!/bin/bash

FILES="/usr/sbin/accept /usr/sbin/pwck/ usr/sbin/chroot"

for file in $FILES
do
  ls -lh $file
done
$ ./arraytest
lrwxrwxrwx 1 root root 10 Apr 24 11:02 /usr/sbin/accept -> cupsaccept
-rwxr-xr-x 1 root root 54K Mar 22 14:32 /usr/sbin/pwck
-rwxr-xr-x 1 root root 43K Jan 14 07:17 /usr/sbin/chroot

前記の friendly2.sh の例に戻り、変数 $@ の中に含まれる値のリストを処理するように変更しましょう。わかりやすくするために、ここでは後者の(個々の値を保持する)変数を username としましょう。 スクリプトは次のようになります。

     1	#!/bin/bash
     2
     3	# a friendly script to greet users
     4
     5	if [ $# -eq 0 ]
     6	then
     7	  echo "Please enter at least one user to greet."
     8	  exit 1
     9	else
    10	  for username in $@
    11	  do
    12	    echo "Hello $username!"
    13	  done
    14	  exit 0
    15	fi

ここで定義した変数の名前は任意であり、配列のそれぞれの要素毎に do…done の中のすべての行が実行されます。スクリプトからの出力を見てみましょう:

$ ./friendly2.sh Carol Dave Henry
Hello Carol!
Hello Dave!
Hello Henry!

続いて、もう少し人間味のある出力にしてみましょう。あいさつを、1行にしたいと思います。

     1	#!/bin/bash
     2
     3	# a friendly script to greet users
     4
     5	if [ $# -eq 0 ]
     6	then
     7	  echo "Please enter at least one user to greet."
     8	  exit 1
     9	else
    10	  echo -n "Hello $1"
    11	  shift
    12	  for username in $@
    13	  do
    14	    echo -n ", and $username"
    15	  done
    16	  echo "!"
    17	  exit 0
    18	fi

いくつかの注意点があります:

  • echo に -n を指定すると、表示後の 改行が抑止 されます。つまり、すべての echoが同じ行に出力されて、16行目の ! の後でのみ改行が表示されます。

  • shift コマンドは、配列から先頭の要素を取り除きます。つまり、これが:

0

1

2

Carol

Dave

Henry

こうなります:

0

1

Dave

Henry

出力を見てみましょう:

$ ./friendly2.sh Carol
Hello Carol!
$ ./friendly2.sh Carol Dave Henry
Hello Carol, and Dave, and Henry!

正規表現によるエラーチェック

ユーザーが入力したすべての引数を確認したいことがあります。例えば、friendly2.sh に渡されるすべての名前が アルファベットのみ であることを確認し、特殊文字や数字はエラーとしたい場合です。この種の確認を行うには、grep を使用します。

grep では正規表現が使えることを思い出しましょう。

$ echo Animal | grep "^[A-Za-z]*$"
Animal
$ echo $?
0
$ echo 4n1ml | grep "^[A-Za-z]*$"
$ echo $?
1

文字 ^ と $ は、それぞれ行の先頭と末尾を示します。[A-Za-z] はアルファベットの大文字と小文字の範囲を示します。文字 * は 繰り返し を示し、文字の範囲がゼロ個以上続く文字列と一致します。つまり grep は、入力がアルファベット のみ である場合に成功し、そのほかの場合には失敗します。

次に注意すべきことは、grep は一致したかどうかに応じた終了コードを返すことです。一致した場合は 0 を返し、一致しなかった場合は 1 を返します。これを利用してスクリプト内で引数をテストすることができます。

     1	#!/bin/bash
     2
     3	# a friendly script to greet users
     4
     5	if [ $# -eq 0 ]
     6	then
     7	  echo "Please enter at least one user to greet."
     8	  exit 1
     9	else
    10	  for username in $@
    11	  do
    12	    echo $username | grep "^[A-Za-z]*$" > /dev/null
    13	    if [ $? -eq 1 ]
    14	    then
    15	      echo "ERROR: Names must only contains letters."
    16	      exit 2
    17	    else
    18	      echo "Hello $username!"
    19	    fi
    20	  done
    21	  exit 0
    22	fi

12行目で標準出力を /dev/null にリダイレクトしていますが、これは出力を抑止する簡単な方法です。 ここでは grep コマンドの出力は不要で、13行目で終了コードをテストしたいだけです。無効な引数を示すために、終了コード 2 を使っていることにも注意しましょう。異なるエラーを示すために異なる終了コードを使うのは良い習慣です。熟練ユーザーは、これらの終了コードをトラブルシューティングに利用します。

$ ./friendly2.sh Carol Dave Henry
Hello Carol!
Hello Dave!
Hello Henry!
$ ./friendly2.sh 42 Carol Dave Henry
ERROR: Names must only contains letters.
$ echo $?
2

演習問題

  1. 以下の script1.sh を見て下さい:

    #!/bin/bash
    
    if [ $# -lt 1 ]
    then
      echo "This script requires at least 1 argument."
      exit 1
    fi
    
    echo $1 | grep "^[A-Z]*$" > /dev/null
    if [ $? -ne 0 ]
    then
      echo "no cake for you!"
      exit 2
    fi
    
    echo "here's your cake!"
    exit 0

    以下のコマンドの出力はどうなりますか?

    • ./script1.sh

    • echo $?

    • ./script1.sh cake

    • echo $?

    • ./script1.sh CAKE

    • echo $?

  2. 以下の script2.sh を見て下さい:

    for filename in $1/*.txt
    do
       cp $filename $filename.bak
    done

    このスクリプトの目的が何かを記述して下さい。

発展問題

  1. 任意個の引数を受け取り、10より大きい数値の引数のみを表示するスクリプトを作成してください。

まとめ

このレッスンでは、次のことを学びました:

  • 終了コードとは何か、また、その意味と実装方法

  • コマンドの終了コードを確認する方法

  • for ループとは何か、また、それを配列と共に使う方法

  • スクリプト内と入力をチェックするために、grep と正規表現、終了コードを使う方法

演習で使用したコマンド:

shift

配列の最初の項目を取り除きます。

特殊変数

$?

直前に実行したコマンドの終了コードを保持する。

$@, $*

スクリプトに渡されたすべての引数を、配列として保持する。

演習の解答

  1. 以下の script1.sh を見て下さい:

    #!/bin/bash
    
    if [ $# -lt 1 ]
    then
      echo "This script requires at least 1 argument."
      exit 1
    fi
    
    echo $1 | grep "^[A-Z]*$" > /dev/null
    if [ $? -ne 0 ]
    then
      echo "no cake for you!"
      exit 2
    fi
    
    echo "here's your cake!"
    exit 0

    以下のコマンドに対する出力は何ですか?

    • コマンド: ./script1.sh

      出力: This script requires at least 1 argument.

    • コマンド: echo $?

      出力: 1

    • コマンド: ./script1.sh cake

      出力: no cake for you!

    • コマンド: echo $?

      出力: 2

    • コマンド: ./script1.sh CAKE

      出力: here’s your cake!

    • コマンド: echo $?

      出力: 0

  2. 以下の script2.sh を見て下さい:

    for filename in $1/*.txt
    do
       cp $filename $filename.bak
    done

    このスクリプトの目的が何かを記述して下さい。

    最初の引数で指定したサブディレクトリから、.txt で終わるすべてのファイルのバックアップコピーを作成します。

発展演習の解答

  1. 任意個の引数を受け取り、10より大きい数値の引数のみを表示するスクリプトを作成してください。

    #!/bin/bash
    
    for i in $@
    do
      echo $i | grep "^[0-9]*$" > /dev/null
      if [ $? -eq 0 ]
      then
        if [ $i -gt 10 ]
        then
          echo -n "$i "
        fi
      fi
    done
    echo ""

Linux Professional Insitute Inc. All rights reserved. 学習資料をご覧ください: https://learning.lpi.org
ここでの作成物は、Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Licenseの下でライセンスされています。

次のレッスン

4.1 オペレーティングシステムの選択 (4.1 レッスン 1)

次のレッスンを読む

Linux Professional Insitute Inc. All rights reserved. 学習資料をご覧ください: https://learning.lpi.org
ここでの作成物は、Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Licenseの下でライセンスされています。

LPIは非営利団体です。

© 2023 Linux Professional Institute(LPI)は、オープンソースプロフェッショナル向けのグローバルな認定基準およびキャリアサポート組織です。200,000人以上の認定保持者を擁する、世界初かつ最大のベンダー中立Linuxおよびオープンソース認定機関です。LPIは180か国以上で認定プロフェッショナルを擁し、複数の言語で試験を実施し、何百ものトレーニングパートナーを擁しています。

私たちの目的は、オープンソースの知識とスキルの認定資格を世界中からアクセスできるようにすることで、誰にとっても経済的で創造的な機会を可能にすることです。

  • LinkedIn
  • flogo-RGB-HEX-Blk-58 Facebook
  • Twitter
  • お問い合わせ
  • 個人情報とCookieポリシー

間違いを見つけたり、このページを改善したいですか? 私たちに知らせてください。.

© 1999–2023 The Linux Professional Institute Inc. All rights reserved.