Bashプログラミング
 Computer >> コンピューター >  >> プログラミング >> Bashプログラミング

「~」の魔法:Bashのチルダ展開を5つの例で解説

「~」の魔法:Bashのチルダ展開を5つの例で解説Bashシェルには、「~」(チルダ)で始まる特殊な変数が用意されており、これらは「チルダ展開(Tilde Expansion)」と呼ばれます。

これらは、シェル内の他の変数の内容を指す別名(シノニム)のようなものです。

チルダ展開とは、これらの省略表記を、それが表す実際のディレクトリ名に変換する処理のことです。この記事では、具体的な例を交えながらチルダ展開の機能を詳しく解説します。

チルダ展開は、「~」に「+」「-」、または整数Nを組み合わせた形で、空白またはスラッシュまでの範囲に適用されます。

チルダ展開は、次のような特定のパス名への展開に使用されます。

  • ホームディレクトリ
  • 現在/直前の作業ディレクトリ
  • ディレクトリスタック上のディレクトリ

ホームディレクトリの展開

チルダ展開を使うと、現在のユーザーのホームディレクトリや、指定したユーザー名のホームディレクトリへ展開することができます。

構文

~      $HOME変数、または現在のユーザーのホームディレクトリに展開される
~USER  指定したユーザー名のホームディレクトリに展開される

例1:現在のユーザーのホームディレクトリ

チルダ(~)が単独の単語として使われた場合、$HOMEが定義されていれば$HOMEの値に展開され、定義されていない場合は現在のユーザーのホームディレクトリに展開されます。

次の例では、HOME変数の値が/home/oracleなので、cd ~を実行するとカレントディレクトリが$HOMEの値に変更されます。

## ホームディレクトリが /home/oracle の oracle ユーザーにログイン
# su oracle
[tmp]$ pwd
/tmp

[tmp]$ echo $HOME
/home/oracle

[tmp]$ cd ~

[~]$ pwd
/home/oracle

ここでHOME変数を/sbinに変更すると、cd ~はユーザーの実際のホームディレクトリではなく、$HOMEの値のみを参照することに注意してください。その後、unset HOMEで$HOMEの値を削除すると、cd ~は/etc/passwdでoracleユーザーに設定されたホームディレクトリへ移動します。つまり、チルダ展開ではHOME変数が実際のホームディレクトリよりも優先されるのです。

[~]$ export HOME=/sbin

[oracle]$ cd ~

[~]$ pwd
/sbin

[~]$ unset HOME

[sbin]$ cd ~

[oracle]$ pwd
/home/oracle

例2:指定したユーザーのホームディレクトリ

次のスクリプトは、ファイル名に現在の日付が含まれるログファイルのバックアップを作成します。また、開始時刻と終了時刻を、oracleユーザーのホームディレクトリにあるbackup.logというファイルに記録します。

#! /bin/bash

echo "Initiating the backup at `date`" >> ~oracle/backup.log

da=`date +%F`
cp $da.log{,.bak}

echo "END BACKUP at `date`" >> ~oracle/backup.log

$ ls -l /home/oracle/
total 8
-rw-r--r-- 1 root   root       99 Jun  4 14:23 backup.log

なお、指定したユーザー名が存在しない場合は、展開は行われません。次の例では「ora」というユーザーは存在しないため、~oraは/home/oraに展開されず、そのまま出力されます。

$ echo ~ora
~ora

Bashにおけるブレース展開({ })の使い方については、以前の記事も参考にしてください。

作業ディレクトリの展開

チルダに「+」や「-」を組み合わせると、作業ディレクトリを表すことができます。

  • ~+:現在の作業ディレクトリを保持するPWD変数の値に展開されます。
  • ~-:直前の作業ディレクトリを保持するOLDPWD変数の値に展開されます。OLDPWDが未設定の場合、~-は展開されません。

例3:旧/現作業ディレクトリの展開

次の例では、現在のディレクトリと直前の作業ディレクトリにあるファイルを比較しています。

$ cat comp.sh
#! /bin/bash

set -x
cd /var/opt/gg
if [ -f gg.c ]
then
echo "File1 exists"
fi

cd /var/opt1/gg
if [ -f gg.c ]
then
echo "File2 exists"
cmp ~+/gg.c ~-/gg.c
fi

$ ./comp.sh
+ cd /var/opt/gg
+ '[' -f gg.c ']'
+ echo 'File1 exists'
File1 exists
+ cd /var/opt1/gg
+ '[' -f gg.c ']'
+ echo 'File2 exists'
File2 exists
+ cmp /var/opt1/gg/gg.c /var/opt/gg/gg.c
cmp: EOF on /var/opt1/gg/gg.c
$

上記の実行結果では、以下のように展開されています。

  • ~+/gg.c → /var/opt1/gg/gg.c(現在のディレクトリ)
  • ~-/gg.c → /var/opt/gg/gg.c(直前のディレクトリ)

この記事は、連載中のBashチュートリアルシリーズの一部です。

ディレクトリスタックの展開

各bashプロセスにはスタックオブジェクトが含まれており、スクリプトがディレクトリ内容を処理する際に訪れたディレクトリを追跡するために使用できます。

これは、ディレクトリを参照したり、以前に訪れたディレクトリに戻ったりするための、非常にシンプルな仕組みです。チルダ展開は、このディレクトリスタック上のディレクトリへの展開にも対応しています。

  • ~+N:ディレクトリスタックのN番目のディレクトリに展開されます(オプションなしで実行したdirsコマンドが表示するリストの左側からゼロ起点で数えます)。
  • ~-N:ディレクトリスタックのN番目のディレクトリに展開されます(同じくdirsコマンドのリストの右側からゼロ起点で数えます)。

dirs、pushd、popdコマンドを使ったディレクトリスタックの操作方法については、以前の記事を参考にしてください。

例4:~+で左からN番目のディレクトリを表示

次の例では、ディレクトリスタックに4つのディレクトリが登録されています。~+2を指定すると、左からゼロ起点で数えて2番目の位置にあるディレクトリパスが得られます。

$ dirs -v
 0  /sbin
 1  /var/opt/midas
 2  /var/opt/GG/bin
 3  /root

$ cd ~+2

$ pwd
/var/opt/GG/bin

ただし、スタックの最上位(ゼロ番目の位置)には常に現在のディレクトリが入ります。したがって、上記の実行後、ディレクトリスタックは次のように表示されます。

$  dirs -v
 0  /var/opt/GG/bin
 1  /var/opt/midas
 2  /var/opt/GG/bin
 3  /root

例5:~-で右からN番目のディレクトリを表示

次の例は上記と似ていますが、~-を使用しているため、スタックの下(右側)からディレクトリが数えられる点が異なります。

$ dirs -v
 0  /var/opt/GG/bin
 1  /var/opt/midas
 2  /var/opt/GG/bin
 3  /root

$ cd ~-2

$ pwd
/var/opt/midas

$ dirs -v
 0  /var/opt/midas
 1  /var/opt/midas
 2  /var/opt/GG/bin
 3  /root
  1. Linuxのwatchコマンドの使い方と実用例をわかりやすく解説

    Linuxのwatchコマンドは、指定したコマンドを一定間隔で繰り返し実行し、その結果を画面に表示し続けるためのツールです。コマンドの出力が時間とともにどう変化するかをリアルタイムで監視したい場合に非常に便利です。この記事では、watchコマンドの基本的な使い方と、覚えておくと役立つ実用的な例を紹介します。 watchコマンドの基本構文 watchコマンドの構文は以下のとおりです。 watch オプション コマンド 各要素の意味は次のとおりです。 オプション: 後述の表から選択したオプションを指定します。watchコマンドのデフォルト動作を変更できます。 コマンド: watchが繰り返し実行

  2. Bashシェル関数入門:実用的な6つのサンプル例で学ぶチュートリアル

    Bashシェル関数とは、複数のUNIX/Linuxコマンドをひとつの名前でグループ化し、後からまとめて実行できるようにする仕組みです。Bashシェル関数は通常のUnixコマンドと同じように呼び出すことができ、現在のシェルコンテキスト内で実行されるため、解釈用の新しいプロセスを生成する必要がありません。bashのエイリアス(alias)と関数はどちらも、長いコマンドや複雑なコマンドに対するショートカットを定義するのに役立ちます。しかし、エイリアスでは制御フローや引数の扱いなど、関数ならではの高度な処理を行うことはできません。本記事では、その違いも含めて詳しく解説していきます。この記事は、進行中の