シェルスクリプトと変数の代入の注意

今回、日経Linux の記事にある
case 文を使った例を実際に行ったところ、エラーがおこり
かなり悩みました
原因は単純で、
newfile=”${file%.*}”.html
とするべきところを
newfile =”${file%.*}”.html
というように、スペースを入れてしまったのが
原因でした
普通の白黒コンソール画面ではわかりにくかったのですが
色付きの画面でみたときに違いがわかりました
newfile=”${file%.*}”.html
とすると
newfile=”${file%.*}”.html
というように
文字が青くなります
しかし、スペースを入れてしまうと
黒い文字となり、エラーとなります
どうやら、スペースをいれると
コマンドとしてみなされるようです
この違いがわからず、かなり悩みました
Cやjava などでは、記述する時にそこまで厳しくないのですが
シェルスクリプトのときにはまったく違う
意味になるようなので、今後の注意点としておきたいと思います

スペースを含む場合の注意点

繰り返し処理を行う for文
において
$@ という記号を使うことにより
すべての引数リストを指定して、複数のファイルを
取扱い可能になりました
しかし、まだ問題点は残されています
このまま、処理を行うと
ある欠点に遭遇します
それは、空白を含むファイルなどをつかうと
エラーになることです
空白を含むファイル名を処理しようとすると
別の引数として認識され、結果としてエラーとなります
このため
for 変数名 in リスト
do
処理
done
としている文章を

for 変数名 in “リスト”
do
処理
done

というように ” “で囲みます
つまり、
for file in “$@”
do
処理
done

のようにすることで、空白を含むファイルも
無事に処理することができるようになります

繰り返し処理を行う for文

複数の引数を処理するような
シェルスクリプトを書く場合、for 文を使用すると便利です
引数をある程度用意しておくのも対策のひとつに
なりますが、使いまわしするには不便です
理由としては、あとでまた引数を追加するのが
面倒なので、という理由ですが
for文の構文は

for 変数名 in リスト
do
処理
done

となります
このときに、リスト の部分には
$1 $2 $3
などというように、すべて記述する必要はありません
シェルスクリプトでは
$# が引数の数を表す記号
であったように
$@
という記号を使って洛に記述できます
$@すべての引数のリスト
という意味になります
このため
for file in $@
dp
ファイルの処理
done
とすれば、引数として指定するファイルの数を気にせずに
複数のファイルを処理することが可能になります
ちなみに、こういった処理の仕方を指定しないと
複数のファイルの処理はできないようです
実際、実験してみましたが
複数のファイルを指定したところ。最初のファイルしか実行できませんでした

シェルスクリプトでif 文 その2

シェルスクリプトでif 文
が長文になりそうなので
わけてみました
それでは、条件式のメモの続きです

num1 -gt num2

これは num1 が num2 より大きければ、という意味です
つまり
num1 > num2
というかんじです
もちろん、逆パターンもあります
それが
num1 -lt num2
です
これは num1 が num2 より小さいなら、となります
num1 < num2
というかんじです
ここまでが比較関連になります
これからが、ファイル検索などになります
-d ディレクトリのパス
ディレクトリが存在しているなら
という意味になります
if [ -f /home/backup ]
としたなら
/home/backup
が存在していれば、という意味になりますし
if [ -f $1 ]
なら引数に入力したディレクトリが存在しているなら
という意味になります
シェルスクリプトなどで使いまわす場合、
基本的にはファイル名や絶対パスを記述してしまうより
$1 など、引数を指定したほうが、あとあと使うときに修正せずにすみます
-e ファイルのパス
ファイルが存在しているなら、という意味になります
if [ -e $1 ]
$1 に入力したファイルが存在しているなら、という意味になります
仮に、/home/wiki/testfile
と入力した場合、
/home/wiki/testfile が存在しているならば、という意味になります
-r ファイルのパス
これは、ファイルが存在し、読み取り可能なら
という意味です
rは。readからきていると思われます
-w ファイルのパス
これも似たようなもので、
ファイルが存在し、書き込み可能なら
という意味になります
-a
たぶん、一番わかりにくいです
これは、論理式のANDと同じ意味です
C, java でいう && というものです
使い方としては
if [ -r $1 -a -w $1 ]
のように使うようです
これは
if [ $1が読み取り可能 && $1 が書き込み可能 ]
という意味になります
つまり、読み書き可能ファイルであれば
という意味になります

シェルスクリプトでif 文

今回も、前回の
便利なシェルスクリプト
の続きになります
今回は、if 文を追加しました
シェルスクリプトでのif文の構文は

if 条件式
then
処理
fi

というように
if で始まり
fi で終わります
また、C言語などでよくある
if else のように使うには
if 条件式
then
処理
else
  処理
fi

というようになります
さて、今回、わかりにくかったところがあるので
メモがわりに記述してみました
if [ $# = 0 ]
という表現があるのですが
これを記述するときには
[ と ] の間には必ず半角スペースをいれないとなりません
これを普通にCやjava のように詰めてしまうと
エラーになります
原因は
[
]
などもコマンドであるためです
じつは、引数で並べてみると
[ コマンド
$# 引数1
= 引数2
0 引数3
] 引数4
という扱いになっています
コマンド、つまり cd とか chown というものと
同じ扱いなので、これらのコマンドを使用するときには
引数の間に空白をいれていたようにすることになります
<例>
chown +x file3
これを、空白をいれずに
chown+xfile3
だとエラーになります
もうひとつわかりにくいのが
$#です
これは引数の数を表す記号です
つまり、
if [ $# = 0 ]
という文の意味は
引数の数が0なら
という意味になります
引数の数が0、つまりないということは
例を出すなら
cd
という入力をした状態です
cd /home/
これだと引数は1になります
また、シェルスクリプトには
様々な条件式があります
シェルスクリプト 条件式
というように検索すると、かなりでてきます
主なもののリンクとしては
シェル・スクリプト・リファレンス INDEX
などがあります
主なものとしては
str1 = stt2
というような、今回の $# = 0 というような使い方です
これは、C や java でいう == みたいなものです
ただし、比較するのは文字列です
str1 != str2
これも同じようなもので
否定形です
~でないなら、という意味です
$# != 0
とすると、引数の値が0でないなら
という意味になります
これも同様に文字列の比較です
これらは割とわかりやすいのですが
数値比較になると、ちょっとわかりにくい表現になります
num1 -eq num2
この場合、数値が同じならという意味になります
C , Javaなら
num == num2
というかんじです
続いて
num1 -ne num2
これは否定形です
さきほどの != と同じ意味ですが
こちらは数値の比較になります

便利なシェルスクリプト

コマンドを打ち込むときに、タイプミスをしたり
打ち込むのが面倒ということが多々あります
そんなときに役立つのがシェルスクリプトです
たとえば、testfile をtestfile2 というファイルにコピーするときには
通常
cp -p testfile testfile2
というようにします
しかし、毎回コピーするときに打ち込むのは面倒なので
ファイル名に2をつけてバックアップするには
vi backup2
でファイルを作成し
内容を
cp -p ${1} ${!}2
として保存
chmod +x backup2
で実行権限を与えて
./backup2 testfile
と実行すれば
testfile2
が作成されます
今回のわかりにくい点は
${!}
という記号です
これは、シェルスクリプトで使う記号で
意味は 引数1
を意味しています
もう少し載せると
$0 がコマンド名
$1 が引数1
$2 が引数2
$3 が引数3
となっていきます
コマンドと引数の関係を cp コマンドで例えると
cp -p testfile testfile2
の場合なら
cp  が $0
tetfile が $1
testfile2 が$2
というかんじです
オプションは引数には入らないはずです
これを活用するとかなり楽になります
ちなみに、今回
vi backup2 の内容で
cp -p ${1} ${!}2
となっていますが
コピーしたファイルの名前をbackupというようにつけたいのなら
cp -p ${1} ${!}backup
というように変更することでできます
このように、引数などを使うと
tr コマンド
で行った作業の
tr -d ‘\r’ < testfile > testfileTmp
mv testfileTmp testfile
についても
vi ModeLF
でファイルを作成し
中身を
#!/bin/bash
tr -d ‘\r’ < ${1} > ${1}Tmp
mv ${1}Tmp ${1}
で保存して
chmod +x ModeLF
とすることで同様の作業ができるようになります
引数を使う最大のメリットは
ファイル名を記述すると、そのファイルにしか適用できないのに対し
引数を指定した場合なら、他のファイル名でも使用できるのが
最大のメリットとも言えます

シェルスクリプトで差分バックアップ

今回は、日経Linux の載っていた記事を参考に、
差分バックアップを実践しています
rsync コマンドを使うことで、差分バックアップをとれます
そこで、
mkdir /mnt/backup
mkdir /home/wiki/MyDoc
で先にバックアップディレクトリを作成し
ここにバックアップをとるように
rsync -a ~/MyDocs /mnt/backup
とすれば、差分バックアップをとれます
そして、これを
cronコマンドで定期的に実行することで
自動差分バックアップのできあがりです
まずは、
vi Backup
でバックアップスクリプトを作成します
内容は
#!/bin/bash
rsync -a ~/MyDocs /mnt/backup
となります
そして、
chmod a+x backup
で実行権限を付与し
crontab -e
で自動設定を行います
そして、
crontab -e の実行したファイルの中で
0 */1 * * * /home/wiki/backup
とすることで、自動バックアップの出来上がりです
今回は、ローカル内のファイルをバックアップ先に指定しましたが
これを、
rsync -a ~/home/wikiBackup /mnt/Backup-server
というように
ファイルサーバーにしたり、外付けのHDDにすることにより
HDD障害に備えることもできます
今回の crontab -e の設定の中身ですが
分 時 日 月 曜日 実行するコマンド
という順番にならんでいます
* はすべての時間を意味します
crontab で設定をすることにより、自動処理が可能になりますので
シェルスクリプトを勉強することで、
より効率的な管理が可能になります

自作コマンドの置き場所

現在、シェルスクリプトの勉強をしてます
主なコマンドの置き場を忘れないように記録してみました
/sbin
重要度の高いシステム管理コマンド
/usr/bin
一般コマンド
/usr/sbin/
システム管理コマンド
/usr/local/bin
パッケージを使わずにインストールした一般コマンド
(多分 make したものとか)
/usr/local/sbin
パッケージを使わずにインストールしたシステム管理コマンド
~/ bin
ユーザごとのコマンド
というかんじです
ちなみに、これは fedora13 の場合で
Ubuntu の場合、ちょっと違います
Ubuntuの場合、~/bin があると、~/.profile により
コマンド検索パスに設定されるので、一度ログアウトが必要になるようです