Unixコマンド行の展開とクォート

シェルはコマンド行を読み込んだ後一定の規則に従って書き換えを行います。そのうち主なものをあげておきます。

  • aliasの展開
  • {}の展開
  • ~の展開
  • シェル変数の展開
  • バッククォートの展開
  • ファイル名の展開

シェルの内部コマンドaliasによって、コマンドに別名を付けることができます。

(実習)次のコマンドを実行し、結果を解釈せよ。
$ type ls
$ alias grep
$ alias
$ alias g='echo がんばって!'
$ g


シェル変数の展開については、「シェル変数」のページで扱います。

{} は、いくつかの文字列の中からマッチする文字列を選択する働きをします。

(実習)次のコマンドを実行し、結果を解釈せよ。{}や,は半角にすること。
$ echo 今日は{雨,晴れ,曇り}です。
$ ls -l /usr/bin/{tiff,pnm,gif,jpeg}to{tiff,pnm,gif,jpeg}

~ は、ホームディクレクトリに関する展開を行います。

(実習)次のコマンドを実行し、結果を解釈せよ。
$ echo ~
$ ls ~
$ echo ~root 

バッククォート ` は、コマンドの出力をコマンド行内に挿入するときに使います。

(実習)次のコマンドを実行し、結果を解釈せよ。違いがあれば、それはなぜか?
$ date
$ echo `date`

ファイル名の展開については、以下の規則が適用されます。
  • *: 任意の文字列とマッチする
  • ?: 任意の1文字とマッチする
  • [...]: ...の中のどれか1文字とマッチする
(実習)次のコマンドを実行し、結果を解釈せよ。
$ cd /usr/bin; echo *
 (何らかの理由でlsが使えないとき、これが役に立つことがある)
$ echo /usr/bin/?
$ ls /usr/bin/?
(注意)ファイル名展開はあくまでも存在するファイル名とマッチするパターンについて行われるので、
$ cp *.c *.c.bak
のような使い方はできません(Windowsのコマンドプロンプトと違う)。これで意図したことを行うには
$ for f in *.c
> do
> cp $f $f.bak
> done
のようにします。これだけを見るとむしろ面倒そうですが、このような制御構造があるため、シェルはプログラミングに使えるのです。詳しくはシェルスクリプトの回で扱います。

このような展開を抑制するには、エスケープまたはクォートを行います。
  • エスケープ:特殊記号の前に?(英語端末の場合はバックスラッシュになる)
  • クォート:特殊記号を含む部分全体を ' または " で囲む
(実習)以下のコマンドを実行し、結果を解釈せよ。
$ cd /usr; echo ?*
$ ls '/usr/bin/*'
$ ls "/usr/bin/*"
' と " の違いには、コマンド置換を行うかどうか(' で囲むと行われず、" で囲むと行われる)の違いの他、シェル変数を扱う際に触れる違いがある。

(実習)次のコマンドを実行し、結果を解釈せよ。
$ echo "current time is `date`"
$ echo 'current time is `date`'

(問)次のコマンドを実行したら何が起きるか?(いきなりやってはいけない)

$ rm *
不用意にこれをやると悲惨なことになる(ことがある)。それにも関わらず、rmコマンドは「本当にいいですか?」というような警告を発しない。なぜか。(わからなければ、コマンド行の展開について調べてから考えてみよ。なお、おせっかいな警告を出すシェルも存在する。)

(問)次のように、シェルを終了するコマンドexitを存在しないコマンド名nonexistentにaliasしたとき、そのシェルを終了させる方法を3つ以上あげよ。(シェルの設定はUbuntuのデフォルト状態を仮定)
$ alias exit=nonexistent
Comments