CUIの世界で暮らす場合、シェルの使いこなしで作業効率は桁違いに変わる。シェルは一種類だけではないが、シェルスクリプトの観点からはsh系とcsh系に分けられる。sh系であるbash(zshでもOK?)をメインに使ってみることにする。純粋な /bin/sh を使うと、declareが使えず、exprとなるのが面倒。

link *

画像整理における実例 *

あえて全部別々に記述してみた。

jpegファイルで、大文字の拡張子を小文字にする(JPG -> jpg) *

for filename in *.JPG
do
  mv ${filename} ${filename%JPG}jpg
done

ダメ写真を削除したなどで、連番が歯抜けとなったjpegファイル群に番号を振りなおす *

declare -i num
num=1
for filename in *.jpg
do
  mv $filename `printf "image%03d.jpg\n" $num`
  num=$num+1
done

プレビュー用にリサイズしたものをImagemagikで作り、previewディレクトリに保存。 *

for file in *.jpg
do
  convert -geometry 160x120 $file ./preview/$file
done

EXIF情報を取り除く *

Imagemagickではできないのだろうか?jpegtranというのを使う。

for file in *.jpg
do
  jpegtran -copy none -outfile $file $file
done

プレビュー用画像をクリックしたら元の画像が出てくるようなHTMLファイルをつくる。 *

declare -i number
declare -i residue
number=1
echo "<body>"
echo "<h1>put a title in EUC....</h1>"
echo "<hr>"
echo ""
echo "<table cellpadding=\"20\">"

for filename in *.jpg
do
  residue=$number%3
  if [ $residue -eq 1 ]
  then
    echo "<tr>"
  fi
  echo "  <td align=\"center\">"
  echo "    <a href=\"$filename\"><img src=\"preview/$filename\" alt=\"\" width=160 height=120 boarder=0></a>"
  echo "    <br> " ## comment
  echo "  </td>"
  if [ $residue -eq 0 ]
  then
    echo "</tr>"
  fi
  number=$number+1
done

echo "</table>"
echo "</body>"

連番 *

参考 - シェルスクリプト総合 その1

例えばshなら

i=1
while test $i -le 10
do
  echo $i
  i=`expr $i + 1`
done

とする。seqコマンドを使っても

$ seq -s ' ' 1 10
1 2 3 4 5 6 7 8 9 10
$ seq -f %03g -s ' ' 1 10
001 002 003 004 005 006 007 008 009 010

と、同様なことができる。整形はprintfコマンドでもOK。

基本 *

スクリプトはコマンドラインから入力しても良いが、慣れないうちは別ファイルとした方が良い。最もお手軽には、コマンドを列挙したファイル hoge.sh を用意して

$ bash hoge.sh

などとする。あるいはファイル冒頭に

#!/bin/bash

などとシェルへのパスを書き、ファイル自身に実行属性を与えても良い。

引数 *

$1, $2, ... 

としてコマンドラインの引数を参照できる。他にも

$0            # スクリプトの名前
$#            # 引数の数
$*            # 全ての引数

など。

変数 *

bash *

変数は基本的に文字列として扱われる。数値としたいならdeclareで指定する。変数の中身を参照する場合は冒頭に$を付す。演算子の両脇に空白を含めてはならない!

declare -i var1
var1=10
var2=20
var1=$var1+1
var2=$var2+1
echo var1,var2,$var1,$var2

なるスクリプトの出力結果は

var1,var2,11,20+1

となる。var2は文字列となっていて、算術演算が反映されていない。

sh *

i=1
i=`expr $i + 1`

などとする。exprの演算子の両脇に空白が必要。

パターンマッチ *

*     任意の文字列
?     任意の一文字
[...] カッコ内のいずれか

これを利用して、文字変数valをいじったものを返すことができる。

${val#pattern}    val前方から最短マッチ部分を除く
${val##pattern}   val前方から最長マッチ部分を除く
${val%pattern}    val後方から最短マッチ部分を除く
${val%%pattern}   val後方から最長マッチ部分を除く

よく使うのは以下の2種類

mypath=/path/to/somewhere/foo.txt
echo ${mypath%.*}   # 拡張子を除く。/path/to/somewhere/foo 
echo ${mypath##/*/} # ファイル名のみを得る。foo.txt

制御文 *

if文 *

以下の様に記述。カッコ前後には空白を挿入すること。

str=hoge # <-- hoge or fuga
if [ $str = hoge ]
then
  echo hoge!
elif [ $str = fuga ]
then
  echo fuga!
else
  echo neither!
fi

条件式に使う等号は、両端に空白を挿入せねばならないみたいだ。

s1 = s2文字列s1とs2が等しい
s1 != s2文字列s1とs2が等しくない
v1 -eq v2数値v1とv2が等しい
v1 -ne v2数値v1とv2が等しくない
-e filefileが存在する

for文 *

このループは、リスト中の要素に対してコマンドを繰り返し実行して、対象が無くなったら勝手に終わるので、Cなどのfor文とは雰囲気が違う。しかし例えば「カレントディレクトリ中のjpegファイル全てに対し○○○を実行する」なんて処理は以下の様に非常に簡潔に書ける。

for filename in *.jpg
do
   ○○○ # <--変数filenameを使って何かをする
done

○○○を'echo $filename'などとすると、jpegファイル名が列挙されるわけである。


Last-modified: Tue, 15 Nov 2005 17:40:42 JST