bash のアレコレ


1. ユーザインタフェースとしての bash

Linux 
lslsls
lsls

  bash 


2. bash の変なところ

 bash  ()
(if,while,)(for,foreach)bash 

bash 




2.1 bash 
bash (C,Java  )C
int a;

a = 5;
printf("%d" , a);
a
 bash 
a=5
a
echo $a
echo 
$

使
 a=5 a =  = 5a=5 

echo a
a $ aa $ 
 bash 
 {} a
echo ${a}

a=1
ab=2
abc=3
echo $abc
 echo $abc 


(一)$abc  ->3
(二)$ab () c  -> 2c
(三)$a ()bc  -> 1bc

3{} 

bash 
a=1
a1
使 bash 
num=1
let num="${num} + 1"
echo $num
2


num=1
num=${num}+1
echo ${num}
 1+1 bash  ${num}+1  "1+1" 

Appendix let
1 + 1
 num 
"" 


2.2 bash 
1  OS()

$1 , $2 ,  $3 ...
 myscript 
myscript first_arg second_arg  third_arg
$1  first_arg $2 , $3 C argv 
()

  $0  $0  myscript 

$#

test a b  c
$# 3C argc 


$$
  PID(ID)PID  $$  使


3. 配列

bash C array  a b c 
array[0]=a
array[1]=b
array[2]=c
  $ C [] n
便 array  a b c 
array=(a b c)

$() ()
  ls_result 
ls_result=$(ls)


Appendix $() ()
 for 便使


4. 制御文

bash  if , while , for , case  使



4.1 if 

bash if
if [ 1 2];then
  
fi
bash if
num1=1
num2=2
if [  ${num1} -eq ${num2} ];then
  echo num1=num2
elif [ ${num1} -gt ${num2}  ];then
  echo "num1 > num2"
else
  echo "num1  < num2"
fi
-eq C ==   -gt  > 
[  ${num1}  [   ${num1} 


(一)if [  
(二)[  ${num1}  
(三)${num1}  -eq  
(四)-eq  ${num2}  
(五)${num2}  ]  

[  bash   ${num1} -eq ${num2}  [  使  bash 

 else , elif 使



4.2 
本来なら if 文の説明の前にこの説明をするべきですが、bash の if 文があまりにも独特な形をしているので、先に制御文の書き方を説明しました。
以下に比較演算子を列挙します。日本語の説明と同時に、同じ意味を表す C における比較演算子を書いておきます。

○数値における比較演算子
構文意味
${num1} -eq ${num2}num1 と num2 が等価の時に真を返します。num1 == num2。
${num1} -ne ${num2} num1 と num2 が等価でないときに真を返します。num1 != num2
${num1} -lt ${num2} num1 が num2 未満の時に真を返します。 num1 < num2
${num1} -le ${num2} num1 が num2 以下の時に真を返します。num1 <= num2
${num1} -gt ${num2} num1 が num2 より大きい時に真を返します。num1 > num2
${num1} -ge ${num2} num1 が num2 以上の時に真を返します。num1 >= num2

2.1節 で bash の変数はすべて文字列であると書きましたが、この比較演算においても例外ではありません。ただ [ コマンドが文字列としての "1" を数値に置き換えて解釈してくれているので、数値としての比較が可能になります。

では次に文字列における比較演算子です。
○文字列における比較演算子
構文意味
-n ${string} string の長さが 0 より大きければ真。strlen(string)
-z ${string} string の長さが 0 であれば真。(!strlen(string))
${string1} = ${string2} 二つの文字列が等しければ真。== ではない のに注意してください。(!strcmp(string1 , string2))
${string1} != ${string2} 二つの文字列が等しくなければ真。strcmp(string1 , string2)
論理演算子の AND(&&) と OR(||) はそれぞれ -a , -o と書きます。
num1=1
num2=2
num3=3
if [ $num1 -lt $num2 -a $num1 -lt $num3 ]; then
echo true
fi
のような使い方になります。




4.3 while 
while if
num=0
while [ $num -lt 5  ];do
  echo ${num}
  let num="${num}+1"
done

0
1
2
3
4
if then dofi  done 



4.4 for 

bash  for C for Cfor 


 
 
 
3
bash  for  VBA   for each VARIABLE in ARRAY 
bash  for 
num=0
for num in 1 2 3 4;do
 echo ${num}
done


1
2
3
4
in num dodone 

3for 便使for 
array=(1 2 3 4)
 array  @ 使
array=(1 2 3  4)
num=0
for num in ${array[@]};do
  echo ${num}
done 
for num in 1 2 3 4;do 
便 for  使
current_files_directories=$(ls)
for temp in  ${current_files_directories[@]};do
  echo ${temp}
done 
(ls)
bash 使

bash 


5. サンプルプログラム

シェルとして bash を使って行うと面倒な作業でも、スクリプトを書いておくとその作業の効率は飛躍的にあがります。ここではそんな例をいくつかっサンプルプログラムとして紹介します。


5.1自分のホームディレクトリ以下にある特定の名前のファイルのみを表示する

仕事の内容ごとにディレクトリを作ってあり、それぞれのディレクトリには必ずその仕事の内容が詳しく書いてある memo.txt というファイルがあるとします。そのファイルを一括に表示するサンプルプログラムです。

/home/user 以下に work1 , work2 , work3 というディレクトリがある。それぞれのディレクトリの中身は以下の通り。
work1: test.txt , memo.txt , main.c , main.h
work2: result.txt , test.cgi , a.conf
work3: memo.txt test.pl , test.f
この場合は /home/user/work1/memo.txt と /home/user/work3/memo.txt のみを表示する。
1: #!/bin/bash 2: target_dir=/home/user #この下に階層的にそれぞれの仕事のディレクトリがある 3: find_file=memo.txt 4: filename=$(find ${target_dir} -name ${find_file}) 5: split="-----" #各ファイルどうしを区切る区切り文字 6: for temp in ${filename[@]};do 7: echo ${split} >> /tmp/mymemo 8: echo ${temp} >> /tmp/mymemo 9: cat ${temp} >> /tmp/mymemo 10: done 11: less /tmp/mymemo 12: rm /tmp/mymemo


: /bin/bash 
2: /home/user 
3: 
4: find_name  find  filename 
5: 
6: filename   temp  
7:  /tmp/mymemo 
8:  /tmp/mymemo 
9:  /tmp/mymemo 
10: 
11:  /tmp/mymemo  less 
12: 使

 find 使bash  for 便


2


23
 $1,$2,$3... 使
target_dir=$1
find_file=$2


2 $# 

1: #!/bin/bash 2: target_dir=$1 3: find_file=$2 4: if [ $# -ne 2 ];then 5: echo "引数は必ず2つ指定してください" 6: exit 7: else 8: filename=$(find ${target_dir} -name ${find_file}) 9: split="-----" #各ファイルどうしを区切る区切り文字 10: for temp in ${filename[@]};do 11: echo ${split} >> /tmp/mymemo 11: echo ${temp} >> /tmp/mymemo 13: cat ${temp} >> /tmp/mymemo 14: done 15: less /tmp/mymemo 16: rm /tmp/mymemo 17: fi

上の例だと引数の数によって判断をしていますが、文字列比較演算子 -n を使うことで、変数 target_dir,find_file の値によっても判断することができます。


5.2 特定のディレクトリに存在するすべてのファイルのバックアップをとる

/home/user/test 以下のファイルを /home/user/test/bak にバックアップをとります。本来ならディレクトリまるごとを圧縮してしまうのが簡単ですが、個々のファイルごとに圧縮しておいた方が便利なので、ここではファイル一つ一つを圧縮します。

今、/home/user/test には 1.txt , 2.txt , 3.txt というファイルがあるとします。
そしてこのスクリプトを実行すると、/home/user/test/bak に 1.txt.bz2 , 2.txt.bz2 , 3.txt.bz2 という3つの圧縮されたファイルが作られる、というのが希望する動作です。

1: #!/bin/bash 2: target_dir=$1 3: target_files=$(find ${target_dir} -maxdepth 1 -type f) 4: end_slash=$(expr ${target_dir} : '.*/$') 5: if [ ${end_slash} -eq 0 ];then 6: backup_dir=${target_dir}/bak$(date +%y%m%d)/ 7: else 8: backup_dir=${target_dir}bak$(date +%y%m%d)/ 9: fi 10: mkdir ${backup_dir} 11: for temp in ${target_files[@]};do 12: outfile=$(basename ${temp}) 13: bzip2 -c ${temp} > ${backup_dir}${outfile}.bz2 14: done

△解説

3: () target_files 
4: /baktarget_dir  bak
 / bak /home/hoge/work /home/hoge/workbak
 expr 使 / 
Appendix expr 使 / / 0 /  0 
5 / 6 ${target_dir}/bak 
8 /  ${target_dir}bak 

bash /home/hoge/test/  /home//hoge////test/  /home/hoge/test/  backup_dir={$target_dir}/bak$(date +%y%m%d%) (/home/hoge/test//bak )

10: 
12: (/home/hoge/test.txt  test.txt )




5.3 CSV 

CSV (,)

CPU,10000
HDD,10000
,6000
,2000
 CSV 

1: #!/bin/bash 2: file=$1 3: money=$(cut -f2 -d, ${file}) 4: sum=0 5: for temp in ${money[@]};do 6: let sum="${sum} + ${temp}" 7: done 8: echo "合計金額は ${sum} 円"

△解説

2: ファイル名を引数に取れることぐらいもう当然 :-)
3: このプログラムの最も大事な部分。
cut -fM -dS FILENAME: M はいくつ目のフィールドを採用するか、S は区切りに使う文字。
4〜 あとはただのループ


6. Appendix

bash プログラミングをする上で知っていると便利なコマンドを列挙します。