シェルスクリプトまとめ1
リモート操作
X を飛ばす
$ ssh -Y -C chino@192.168.1.1
-Y
: X の転送指定
-C
: 通信内容の圧縮。付けると応答性がよくなる。
SSH 越しにコマンドを 1 つだけ実行する
$ ssh chino@server /scripts/do_backup.sh
検索
$ grep -r -i -E "(香風|かふう|カフウ) ?(智乃|ちの|チノ) | Kafu Chino" /var/share/
-i
: 大文字小文字の違いを無視
-E
: 正規表現を使う
仮想端末
インストール
$ sudo apt-get install tmux
有効化
$ tmux
再接続
$ tmux attach
切断
Ctrl
+ B
→ D
※ 切断してから exit しよう
画面の生成
Ctrl
+ B
→ C
画面の切り替え(次へ)
Ctrl
+ B
→ N
画面の切り替え(前へ)
Ctrl
+ B
→ P
画面の分割(縦)
Ctrl
+ B
→ "
画面の分割(横)
Ctrl
+ B
→ %
画面の移動
Ctrl
+ B
→ ↑
, ↓
→
, ←
画面サイズの変更
Ctrl
+ B
→ Ctrl
+ ↑
, ↓
, →
, ←
画面のスクロールの有効
Ctrl
+ B
→ [
※ Q
で元の状態に戻る。
履歴
検索機能(後方検索)
Ctrl
+ R
逆方向(前方検索)にもコマンド履歴の検索をするには・・・
.bashrc
にstty stop endef
を追記する。
検索機能(前方検索)
Ctrl
+ S
端末間でコマンド履歴を共有する
.bashrc
に追記
function share_history { history -a history -c history -r } PROMPT_COMMAND='share_history' shopt -u histappend export HISTSIZE=9999
scp
ローカルのfile.txt
を 192.168.1.1 の/tmp
配下にコピーする。
$ scp ./file.txt chino@192.168.1.1:/tmp/
ログインに使ったユーザのホーム
chino@192.168.1.1:~/
他のユーザのホーム
chino@192.168.1.1:~Cococa/
chino@192.168.1.1:../../tmp/
リモートのfile.txt
を ローカルにコピーする。
$ scp chino@192.168.1.1:/tmp/file.txt ~/
ディレクトリごとコピーする
$ scp chino@192.168.1.1:/tmp/*.log /tmp/
$ scp -r chino@192.168.1.1:/tmp/results/ /tmp/
サーバからサーバにファイルをコピーする
$ scp chino@rabbithouse:/data/file chiya@amausaan:/backup/
システムの過負荷
top
システムの負荷に関する情報を、数秒間隔でリアルタイムに更新しにながら表示
load average
: 負荷の指標。CPU に処理されるのを待ってる仕事の数。1 分あたり平均で何個分の仕事が積み上がっているのかを表す値。CPU のコア数以下ならよい。
%CPU
: CPU 使用率。
TIME+
: CPU 時間。実際に CPU を使ってる時間。
過負荷の原因を探るときは「CPU 使用率が高い」、「CPU 時間も長い」プロセスがあるかどうかを見る。
C
キーを押すとコマンドの詳細表示が切り替わる。
PID
: プロセス ID
$ sudo kill プロセスID
Shift
+ P
・・・CPU 使用率でソート
Shift
+ T
・・・CPU 時間順でソート
Shift
+ M
・・・メモリー使用量順でソート
ログファイルの閲覧
$ grep "/redmine" access.log | grep -v "/live" | less
-v
: 指定の文字列を含む行を除外する
圧縮されたログファイルを grep
zcat
: 圧縮ファイルを読み込んで内容を展開しながら出力する(gzip 形式専用)
$ zcat access.log.gz | grep "/redmine" access.log | grep -v "/live" | less
zcat
: .gz, .tgz 形式
xzcat
: .xz 形式
unzip -p
: zip 形式
リアルタイム出力
$ tail -F access.log | grep "/redmine" access.log | grep -v "/live"
シェルスクリプト
シェルスクリプトを作成する。
$ vim setup.sh
実行権限を変更する。(新しく作ったシェルスクリプトはまだ実行権限が付与されていない)
$ chmod +x setup.sh
シェルスクリプトを実行する
ファイル名だけでコマンドとして実行できるのは、ファイルが/bin/
や/usr/bin/
などの特別な場所にあるときのみ
$ /home/chino/setup.sh
$ ./setup.sh
$ ~chino/setup.sh
変数
#!/bin/bash base=/var/log/nginx latest=${base}/access.log prev=${base}/access.log.1.gz cat $latest | analyze_latest.sh max zcat $prev | analyze_prev.sh max tar xvf log_result_max
tar xfv <path>
: ファイルを展開
tar cfv <path>
: ファイルを圧縮
環境変数
自分で定義しなくても$変数名
と書くと値を参照できる特殊な変数。
$HOME
: ホームディレクトリのパス
$PWD
: 現在のディレクトリのパス
$EDITOR
: 既存のテキストエディタのパス
$PAGER
: 既存のページャー(less, lv など)のパス
$USER
: 現在のユーザのユーザ名
$GROUP
: 現在のユーザののグループ名
$HOSTNAME
: そのマシンのホスト名
コマンド置換
$(コマンド列)
または`コマンド列
`
$ mv result.txt result-$(date +%Y-%m-%d).txt
必要な情報を取り出す
cut
・・・パイプで渡された内容の各行から必要な部分を切り取って返す
$ cat /var/log/nginx/access.log | grep -v "/live" | cut -d " " -f 7 | less
"-d": 区切り文字。(一文字だけしか指定できない)
"-f": 取り出す位置
アクセスされた日付だけを取り出す。
$ cat /var/log/nginx/access.log | grep -v "/live" | cut -d "[" -f 2 | cut -d "]" -f 1 | less
同じ内容の行を数えたい
uniq
・・・連続した重複を取り除く
sort
しておけば、すべての重複をきちんと取り除ける。
uniq -c
・・・それぞれの内容が何回登場したか、が出力される。
アクセスされたページのパスの一覧に対して、同じパスの登場回数を数える
$ cat /var/log/nginx/access.log | grep -v "/live" | cut -d " " -f 7 | sort -r | uniq -c | cat
-r
: 降順ソート
上位と下位の項目を抽出する
上位
$ cat /var/log/nginx/access.log | grep -v "/live" | cut -d " " -f 7 | sort -r | uniq -c | head -n 20
-n
: 出力する行数を変える
下位
$ cat /var/log/nginx/access.log | grep -v "/live" | cut -d " " -f 7 | sort -r | uniq -c | tail -n +6
-n +
: 指定行数以降を出力する。
-n -
: 指定行数以外を除いた全ての行を出力する。
CSV ファイルの並び替え
1,2,3,4,6 列目を取り出す。
$ cat test.csv | cut -d "," -f 1-3,4,6 | sort -t "," -k 3 -n | cat
-t
: 区切り文字の指定
-k
: 指定した列の内容で並び替え
-n
: 数の部分を数値として解釈して数の大小で並べ替える
※ cut と sort でオプションの名前が違う。
結果を上書き出力
$ cat test.csv | cut -d "," -f 1-3,4,6 | sort -t "," -k 3 -n > sorted.csv
>>
: 追記
オプション引数
#!/bin/bash source=$1 target=$2
$ ./script.sh first second third
first・・・$1
second・・・$2
third・・・$3
名前付き引数
#!/bin/bash while getopts b: OPT do case $OPT in b) base="$OPTARG" ;; n) next="$OPTARG" ;; p) previous="$OPTARG" ;; o) output="$OPTARG" ;; esac done
$ ./opt_script.sh -b /var/log/nginx/access.log2.gz -n /var/log/nginx/access.log.1.gz
処理分岐
$ script.sh foo bar
if [ $# = 2 ] # 引数の個数が2に等しい then echo "Hello!" else echo "Good afteroon" fi
target=$1 if [ "$target" != "" ] # 引数が渡された then echo "Hello!" else echo "Good afteroon" fi
繰り返し
#!/bin/bash for filename in rabbithouse.log fleur_du_lapin.log amausaan.log do ./create-report.sh $filename done
#!/bin/bash for filename in `cd /var/log/nginx; ls *.log | grep -v error.log` do ./create-report.sh $filename done
シェル関数
#!/bin/bash # 主要な処理をmain関数として先に定義しておいて最後にそれを呼び出すのが定石 main() { report rabbithouse.log rabbithouse-${today}.csv /shared/rabbithouse/reports report fleur_du_lapin.log ${today}.csv /shared/fleur_du_lapin/reports report amausaan.log ${today}.txt /shared/amausaan/reports } today() { date +%Y-%m-%d } report() { source=$1 report=$2 outdir=$3 ./analyze_mail_log.sh $source $report mkdir -p $outdir mv /tmp/${report} ${outdir}/ echo "$source を処理しました" } main
exit 1
: スクリプトの実行を中断して終了ステータスを 1 にする
return 1
: 関数の実行を中断して終了ステータスを 1 にする
※ 関数のなかで$1
と書くと、シェルスクリプトの引数ではなく、関数の引数を参照する。ので、関数内で引数を参照するときは関数外でいったん別の名前の変数として定義しておく。