1.bash概要
Linuxのbashはforなどのループや変数が使えるなど、意外に便利である。
(1)いろいろ
・コメントは#
・複数の命令をつなげる場合は; ※このあたりはPythonでも同じ
・Linuxでは、デフォルトでbashが使われる。
使えるシェルのリストの確認(?あってるかな?)は、以下
#cat /etc/shells
/bin/sh
/bin/bash
/bin/rbash
/bin/dash
(2)まずは作成してみよう
たとえば、以下のファイルを作る。test.sh
#!/bin/bash echo "hello"
実行する
#chmod +x test.sh #実行権限の付与 #./test.sh hello
何点か補足する。
・冒頭にbashのパス(/bin/bash)を記載する。ちなみにこの1行目のことをシバンと言う。
・このパスについては、whichで確認しておくのが確実だ。
#which bash
/bin/bash
(3)作業時の注意点 WindowsでファイルをUpload
Windowsでファイルを作ってUploadしても、文字コードの関係でうまく実行できなかった。viで開いても同じなのだが、fileコマンドで見ると、ファイル形式が違うという。そして、実行してもエラーになる。
→解決策
Windowsでファイルを作ってLinuxに送る場合、UnicodeはUTF-8(BOM無)、改行コード LF onlyとする。こうしないと、Linux側でうまく実行されない。
まあ、ファイルをUploadするときは、TeraTermのSSH SCPがいいだろう。
http://sm.seeeko.com/archives/21206156.html
(4)historyコマンド
❶概要
・bashのコマンド履歴を表示する。
・ファイルとしては、 .bash_history
ファイルのありかは、ユーザのホームディレクトリ。
❷bashのhistoryを消す
・コマンドで実行
history -c
ただ、history -c はログインしたユーザが実行した履歴のみの削除かもしれないので、ユーザ毎に、以下もしておいたほうが安心かも。
・historyファイルを直接編集
vi ~/.bash_history
以下はごっそり消す方法
cat /dev/null > ~/.bash_history
履歴はログアウト時に .bash_history に書き込まれるので、上記コマンドを実行直後は、ファイル
が存在しないであろう。
また、history -c をしても、.bash_historyが消えていない気がするが、単に書き込んでいないだけかもしれない。
2.文字の出力とecho
(1)基本
echoで文字を出力できる。どれでくくっても、同じ結果になる。基本は"でくくるのかな?
echo abc # => abc echo "abc" # => abc echo 'abc' # => abc
(2)変数を出力
❶シェルで変数を使う。
めちゃくちゃ簡単。シェルに書かなくても、コマンド上に打ち込んでもいい
書き方は以下のように、 " と ’ と 何も囲わないというのがあるが、まあ、" がいいのではないか。
IP1=192.168.1.1 IP2="192.168.1.1" IP3='192.168.1.1' echo $IP1 # => 192.168.1.1 echo $IP2 # => 192.168.1.1 echo $IP3 # => 192.168.1.1
・以下のように、echoで出力する場合、シングルクォートで囲うと変数ではなく、そのまま文字列として表記される。
echo IP=$IP2 # => IP=192.168.1.1 echo "IP=$IP2" # => IP=192.168.1.1 echo 'IP=$IP2' # => IP=$IP2 ※変数ではなく文字として出力
・変数と普通の文字が混在する場合、{}で変数を囲うといいだろう。以下は囲わない場合と囲った場合の違い。
echo "IP=$IP2desu" # => IP= echo "IP=${IP2}desu" # => IP=192.168.1.1desu
❸環境変数を消すときは、unset。このとき$はつけない。
# unset IP
# echo $IP
(3)echoでファイル出力
❶echoで新規ファイルを作成する
❷改行コードなどを入れる場合
改行コードなどを入れるには-eのオプションをつける。
改行コードは\n、"や$などは\によって\"、\$とする。
echo -e "<html>\n<body>\n<form action=longin.php method=\"POST\">\n<div>" >login.php
(4)catでファイル出力
echoでファイルを作る場合、ソースファイルを整形しなくてはいけないのが面倒。そこで、以下が便利。
構文としては、以下で、ファイル名を指定する。終わりはEOF。
cat <<'EOF' > file.txt I am a boy EOF
このとき、EOFを'EOF'としてシングルクォートで囲うと、$などの変数展開がされない。
なので、たとえば、以下のようなスクリプトもそのままbashで流し込むことができる。
#index.cgiを作成 cat <<'EOF' > index.cgi #EOFを'でクォートしないと、$が変数として展開されてしまう。 #!/bin/perl use CGI; use CGI::Cookie; my $cgi = new CGI; my $url =$cgi->param('url'); if ($ENV{'QUERY_STRING'} ne '') { if ($url ne '') { print "Location: $url\n\n"; } print $cgi->header; } else{ print $cgi->header; my %cookies = fetch CGI::Cookie; if (exists $cookies{'SID'}) { $value = $cookies{'SID'}->value; if ($value eq 12345){ print "success"; } }else{ print "hello"; } } EOF
3.if文やループ
(1)if文
and条件やofもつけられる。
基本構文は、こんな感じ。
if then elif else fi
❶文字が一致するか
・文字を比較するときの構文であるが、 という2重カッコがよく使われる。これ以外にも[] やtestを使うなどもできる。
・[[の後ろに空白がいるなど、ちょっとしたことで動かないので注意
以下は、IPアドレスを入力させて、1.1.1.1であればcorrect そうでなければnot correctと表示するもの。
#!/bin/bash read -p "Tell me IP address:" ip if [[ $ip = "1.1.1.1" ]] then echo "correct" else echo "not correct" fi
❺ファイルが存在するか
以下は、a2.shが存在するかを確認する。-f でファイル名を指定する。
#!/bin/bash #read -p "Tell me IP address:" ip if [[ -f "/root/a2.sh" ]] then echo "correct" else echo "not correct" fi
※ディレクトリが存在するかを調べる場合は、-fの代わりに-dを使う
(2)forによるループ
❶Cのような書き方
これはCのような書き方で、個人的にはわかりやすい。bashでしかできない構文のようだ。
sleep 5として、5秒間隔で実行させている。カッコを2つ、((で囲う点に注意
#!/bin/bash for ((i=1 ; i<5 ; i++)) do echo $i done
❷シンプルな書き方
#!/bin/bash for i in {1..4}; do echo $i done
❸配列の値を回す
#!/bin/bash student=(Ito Suzuki Takana) for name in ${student[@]}; do echo "name=$name" done
❹ループを回してコマンドを実行
以下は、user1からuser5をループで削除する場合
forでiの値を1~5で変化させる。そして、変数をコマンドに入れるには、${i}という記述をする。
for i in {1..5};do userdel -rf user${i} done
→watchコマンドやwhileでもできるようす。
watch -n 5 echo "Hello"
4.配列
配列も使えるので、とても便利だ。
(1)配列への入力と表示
❶配列に値を入れて、出力するいくつかのパターンを例示する。
#aという配列に以下の5つの値を入れる a=(1 ab 2 cd 3) a=("1" "ab" "2" "cd" "3") #ダブルクォーテションで閉じた方が無難だろう。 #配列の1つ目、2つ目を表示 echo ${a[0]} # => a echo ${a[1]} # => ab #配列を指定するとどうなるか echo $a # =>1 先頭の1のみ出力 echo ${a[@]} # =>1 ab 2 cd 3 全て出力 #配列の要素数を出力 echo ${#a[@]} # =>5 配列の要素の数を出力
❷dateという結果を配列に入れて、時刻だけを取り出した様子。結構使えそう。
date # => Wed 21 Oct 2020 10:50:10 PM UTC b=(`date`) echo ${b[4]} # => 10:51:15
(2)配列の値の変更
❶配列に値を追加
a=(1 ab 2 cd 3) a+=(ef) # => efを末尾に追加 echo ${a[@]} # => 1 ab 2 cd 3 ef
❷値の変更
1つ目の値を6に変更する。
a=(1 ab 2 cd 3) a[0]=6 #a[0]の値を6に echo ${a[0]} # => 6
5.コマンドラインで引数を渡す
(1)コマンドラインの引数
実行時にコマンドラインの引数を渡す
・以下のように、pg1.shを実行時に、コマンドライン引数として10、20、30を渡したとする。
# ./pg1.sh 10 20 30
すると、プログラムの中では $1 $2 $3 にそれぞれ値が入れられる。
pg1.shを以下とする。
echo "number1=$1" echo "number2=$2" echo "number3=$3"
出力結果は以下
number1=10 number2=20 number3=30
(2)ユーザに入力を求める
・以下は、ユーザにIPアドレスを入力してもらい、それを変数に入れるシェルであるa.sh。今回はechoで出力もしている。
#!/bin/bash read -p "Tell me IP address:" ip echo "IP address=$ip"
結果は以下
# ./a.sh Tell me IP address:10.1.1.1 IP address=10.1.1.1
6.ファイルを読み込んでの処理
(1)まあ、いろいろやり方はある
以下の方法がシンプルかと。
❶テキストデータを読み込み
テキストにあるデータを1行ずつ読み込み、ループ処理をする。lineというのは単なる変数(だと思う)。違う文字でもできるはず。
以下は、単に表示するだけ
#!/bin/bash cat ./list.txt | while read line do echo $line done
もちろん、$lineを変数として、コマンドの処理もできる。その場合は、 ${line}として、他の文字と混在しないようにした方が無難だ。
7.その他
(1)標準出力関連
❶結果をファイルに出力する
ls -l > a.txt
❷標準出力とファイルの両方
・teeを使う
ls -l | tee a.txt
・または、以下のようにパイプでつなぐことが多いと思う
ls -l | tee a.txt | more ls -l | tee a.txt | grep word
(2)いろいろ
❶コマンドの実行結果を変数に入れる
以下のようにバッククォートを使い、その中にコマンドを入れる。
VPC_ID=`command`
echo ${VPC_ID}
❷JSON形式の操作
・事前にJSON形式の処理をするために、jqをインストール
yum -y install jq
・たとえば、以下のようなJson形式のファイルがあった場合、VPCの中のVpcidを取得したいとする。
{ "Vpc": { "VpcId": "vpc-xxx", "InstanceTenancy": "default", "CidrBlo・・
コマンドは以下。-rでダブルクォートを外している。
jq -r '.Vpc | .VpcId'
または、以下がいいかも
jq -r '.RouteTables[].RouteTableId'`