シェルとコンパイル
unixの醍醐味。cygwinでも使えます。
シェルスクリプト(sh, csh)
エスケープ大会
シェルのコマンドラインでは、&, (, ), |, ^, <, >, ?, *, [, ], $, `, ", ', {, }は特殊文字なので、エスケープしないといけない。\を付ける方法と''(シングルクォート)で囲む方法があるが、ある程度複雑になったら''で囲むほうがお勧め。
echoで( (カッコ)や"(ダブルクォート)を表示させるには、次のどちらかを用いる。
echo '(123"'
echo "\(123\""
echoで$(ドル記号)を表示させるには、
$ echo '$'
echoで'(シングルクォート)を表示させるには、""で囲む。
$ echo "'"
これを組み合わせれば、一通り何でも書ける。
$a='abc'; print "a=$a\n";
をperl -e で実行するには
perl -e '$a='"'"'abc'"'"'; print "a=$a\n";'
となる。('を"'"としてエスケープ、$は'で囲んでエスケープ)
ループしたい!
-
shでループを回す。
n=0
while [ $n -lt 10 ]
do
echo $i (お好きなコマンド)
n=`expr $n + 1`
done
一行にこだわるなら
n=0; while [ $n -lt 10 ]; do echo $i; n=`expr $n + 1`; done
あるいは、コマンドseqとかjotとかがあれば
for i in `seq 1 10`
do
echo $i
done
-
連番の番号が付いたファイルをダウンロードしたい。
上のecho $iのとこを書き換える。だから、
for i in `seq 1 10`; do wget http://ww.hoge.com/${i}.jpg; done
とかする。
-
クラスタのノードをまとめて再起動。
hoge000からhoge099を指定しています。
for i in `seq 0 99`
do
ssh `printf hoge%03d $i` reboot
done
-
for文で色んな引数で関数を呼び出す
eat(){
echo "Eating $1"
}
hosts="apple orange banana"
for h in $hosts
do
eat $h
done
-
画像変換。png からjpgに。
#!/bin/sh
for f in *.png ;do convert $f `basename $f .png`.jpg; done
サイズを1024x768に。
cd vr_pc
for f in *.jpg ; do
convert -size 1024x768 $f orig/$f ;
done
-
引数の画像を、画質を色々変えてJPEG変換。
#!/bin/sh
m=$1
n=5
while [ $n -lt 100 ]
do
convert -quality $n $m.pgm $m$n.jpeg
convert $m$n.jpeg $m$n.pgm
./a.out $m.pgm $m$n.pgm
ls -s $m$n.jpeg
n=`expr $n + 5`
done
-
なんとか.origというディレクトリ内の画像を連番(00.png-99.png)にリネームし、ついでにサイズを800x600に変える。
i=0
for f in $1/orig/*; do
convert -resize 800x600 $f $1/`printf %02d $i`.png
i=`expr $i + 1`
done
その他、shのtips
-
もしファイルが存在したら何かする。
if [ -e /etc ] ; then echo "/etc exists" ;fi
-
exprを使うと、シェル(sh)でマッチとか数値処理が出来る。
例えばある文字列が絶対パスか相対パスか調べる。
$ expr /home/kei/ : /
1
/から始まる文字列だと1を返し、そうでないと0を返す。
-
CVSリセット!
find . -name "CVS" | xargs rm -rf
CVSという名前のフォルダが全て消去されます。
-
とあるサーバから撤退することにしたんだけど、ここftpしか出来なくて、
ファイルをまとめて取ってきたりするのはけっこう不便。
というわけで書いた危険スクリプト。
#!/bin/sh
cd ..
tar czvf public_html.tgz public_html/*
mv public_html.tgz public_html
print "Content-type:text/html;\n\nall done";
これで普通のcgiみたいにアップしてパーミッション変えて、外から実行したらちゃんと
圧縮ファイルが出来てました。でもよい子は真似しちゃだめ!?
-
shでコマンドの結果を変数に代入。例えば、条件に合うファイルの個数を表示
i=`ls |wc -l`
echo $i
wc -lっていうのは行数数えるコマンドです。
-
この前に実行したgから始まるコマンドを実行したいときは、
$ !g
gcc test.c -o test.out
でOK。だけど、前に実行したコマンドに自信が無いときや、ちょっとだけ変更して実行したいときは、下のようにすると良い。
$ #!g
# gcc test.c -o test.out
こうすると、#が付いてるからコマンドは実行されないけど、直前に実行したコマンドとして# gcc test.c -o test.outが入ってるから、これを上矢印で呼び出して、書き換えたらけっこう楽。
$ #!g
# gcc test.c -o test.out
$ gcc test.c -o test2.out -O3
特にコンパイルのオプション変える時とか重宝します。
-
$commandの出力にファイル名として日付をつける
$command > `date +"result.%H%M%S"`
-
このディレクトリ以下の条件に合うファイルについて、コマンドを実行する。
$ find . -name "*.html" -exec ls -l {} \;
{} に引数が入る。\;はコマンドの終わりを示すのに必要。
-
このディレクトリ以下の全htmlファイルについて、文字コードをEUCに変換
$ find . -name "*.html" |xargs qkc -e
xargsは引数をつなげるコマンド。qkcはnkfの高機能版みたいな。
-
rpm -qaしたリストから、ひたすらrpmを削除するスクリプト。
Redhatとかをすっきりさせるために。
#!/usr/bin/perl
$str = "rpm -e ";
foreach(<>){
chomp();
$str .=$_ ." ";
}
`$str`;
-
bash(sh)でディレクトリ付きのパス名からファイル名を抽出
$ hoge=/home/kei/hoge.txt
$ echo $hoge
/home/kei/hoge.txt
$ echo ${hoge/*\//}
Csh
-
普段はtcsh派なので、cshを使おうと思ったらいまいち慣れない。
ディレクトリ中全ての.jpgファイルを.jpegに置換するスクリプト
cd hoge
pwd
rm -f Thumbs.db
foreach f (*.JPG)
mv $f `basename $f .JPG`.jpeg
end
foreach f (*.jpg)
mv $f `basename $f .jpg`.jpeg
end
cd ..
なんだけど、上のループで一つもマッチしないとそこでスクリプトが停止してしまう。
多分エラーを無視みたいなオプションがあるんたろうけど…
-
cshでもループを回す
set i=0
while ( $i <= 10 )
echo $i
@ i++
end
としましょう。スペースの場所に気をつけて。「ディレクトリースタックの番号指定が深過ぎます.」といわれる時は、不等号の後のスペースを確認して下さい。(<= 10ってとこ)
比べると、確かに"C"っぽいですねえ。
-
上ので、色々実験してるうちに見つけた小技(?)。
csh系では、$=0って変数にディレクトリスタック(pushdしたディレクトリたち)が入っているらしい。下のように操作するとちょっとキーボード打ちが少なくなる…かな?
$ cd ~/hoge
$ pushd ~/fuga
$ echo =0
/home/kei/fuga
$ echo =1
/home/kei/hoge
$ cp =0/fugafile =1/hogefile
うーん、でもあまり使い出がない技だな…
連番でユーザーを作成するスクリプト。例えばx01からx50までの50個のアカウントを作成する。
$flag = 1;
sub my_adduser($){
my $uid = $_[0];
$useradd_str = "useradd $uid -g 10000 -p hogehogehoge -s /bin/bash";
$mkdir_str = "mkdir /home/$uid/";
if ($flag){
print $useradd_str . "\n";
#print $mkdir_str . "\n\n";
}
system($useradd_str);
#system($mkdir_str);
}
sub populate(){
foreach $uid ("x01".."x50"){
my_adduser($uid);
}
}
populate();
populateのhogehogehogeところには、crypt("パスワード", "適当な文字列")とした結果を入れる。
例えば一行スクリプトで
$ perl -e 'print crypt("hello", "ho") . "\n"'
として、出力された結果をhogehogehogeの代わりにいれる。
コンパイル(主にgcc)
-
あるディリクトリ以下からテキストをサーチ。
$ grep "pthread_create" `find -name "*.c"`
-
コンパイル時にUndefined Symbolsって怒られたときは、"-lなんとか"でリンクする。
/usr/lib/にあるlibhoge.aなら、-lhogeでいいことが多い。
どのファイルをリンクするか分からないときは、
nm -o --defined-only *.a | grep シンボル名
とすると、リンクしたいファイル名が分かる。
あと、lddでコンパイル済みのバイナリから、リンクされているライブラリが分かる。
-
make -j2で並列コンパイルできます。これだと2プロセス同時にgcc(とか)が動きます。
-
antの基本。
<?xml version="1.0" encoding="EUC-JP"?>
<project name="graph" default="compile" basedir="." >
<property name="class_dir" value="./classes" />
<target name="compile">
<mkdir dir="${class_dir}" />
<javac srcdir="./" destdir="${class_dir}" encoding="EUC-JP" debug="no" />
</target>
<target name="clean">
<delete dir="${class_dir}" />
</target>
</project>