個人的なメモです。今も昔も最も見返す回数が多いですが超古いの多いし中途半端です。
更新しやすくなるかと思うので一応のせてみます。ネタ元やもっと詳しいページリンクを追記したりとかそのうち気が向いたら。
※ぱっと見て分かりやすいサンプルと備忘録的な簡単説明のみ掲載。
詳しくはmanみるかぐぐるか実際に使ってみたらいいとおもいます。(他に影響の少ない環境で。)
載ってない便利なやつの情報あれば大歓迎です。
▽他の便利なやつご紹介
・1行プログラミング
http://www.commandlinefu.com/commands/browse
目次
★awk
★cut
★sed
★grep
★sort
★join
★paste
★perl
★scp
★tar
★date
★find
★zip
★split
★xaugs
★文字化ける時
★shell
・演算オプション
・ループ処理(for)
・特殊な変数
・正規表現
★awk
nawk -F: '{FS=","; print $2}' ./user3.txt
カンマで区切られたフィールドの2番目のカラムをファイルから抽出する
grep keyword file | awk '{FS=",";total+=$20}; END {print total}'
ファイルの中から検索文字列が含まれる行の20カラム目を全部足して出力。
cat file | awk '{FS=",";print $2 + $3 + $4}' | sed -e 's/^/,/g' > res.file
ファイル内容を渡して、2,3,4カラム目を足して行頭をカンマに置換して結果ファイルに出力。
cat ../rev/2x2.xx.xx.rev | awk '{print $4,$2,"A","2x2.xx.xx."$1}' | sed 's/.domein.net.//g' | perl -pe 's/ /\t/g' | tail -255 >> domain.zone
ダブルクォートで追加したい文字列を入れてるのと、空白をタブにしてる。
大量のレコードを逆引きのゾーンファイルから正引きのゾーンファイルに追記したい時用。
cat access_log.20100421|egrep -E -o "HTTP/1.1\" [0-9]* [0-9]*">aaa
PAGE_NUM=`egrep -a '.php |.html ' access_log.20100421|wc -l`
cat aaa |sed -e 's/-//g' -e '/^$/d'|awk '{TOTAL+=$3/$PAGE_NUM/1024};END{print TOTAL}'
Webページ1枚あたりの平均ファイルサイズ (KB)を出す。※1日分。
参考URL:
http://uguisu.skr.jp/Windows/awk.html
★cut
cut -d: -f1 file
fileのコロンで区切られたフィールドの1番目のカラムを標準出力に表示する
cat SUMI.MT.20070401.001|grep '^2.* 44017317 '|cut -c64-70|awk '{sum+=$1} END{print sum}'
MTファイルから、接続料のデータレコードを出して、64文字目から70文字目を切り出してawkで列を足し算。
★sed
sed -e 's/^ //g' -e 's/ \{1,100\}/,/g' file-a > file-b
file-aの先頭のスペースを全行削除して1~100までの連続したスペースをカンマひとつに変換しfile-bに出力する。
sの前に行数を指定することもできる。
※同じこと(スペースをまとめる)がtr -s ' 'でできます。
sed -e '5,10d' file
ファイルの5行目から10行目を削除する
sed '/^$/d' sample.txt
空白行を消す
sed -e '/error/i ##check-line###' log.file
ログファイルにerrorがあったらチェックラインを追加
sed -i 's/enabled = 1/enabled = 0/g' /etc/yum.repos.d/rpmforge.repo
直接中身を書き換えている(iオプションの後ろに.bkなどのサフィックスを指定するとバックアップファイルが作られます)
head -1 log |sed 's/ [^ ]*@/ XXX@/g'
2010/04/01 00:00:24 sent 30000 XXX@softbank.ne.jp 123.123.60.252 XXX@hoge.net
メールログっぽいもののアカウントをマスクしてる(調査依頼時用)
[^ ]はスペース以外のすべての文字列と記号をあらわす正規表現。
ec2-describe-instances -K ./pk-oscaws.pem -C ./cert-oscaws.pem --region ap-southeast-1 --show-empty-fields |sed -e 's/, \{0,10\}/,/g' -e 's/\t\{1,100\}/,/g' -e 's/^TAG,[^ ]\{1,100\}/&\n-------------------------------/g'
カンマとスペースを全角スペースに変えてタブをカンマにしてTAGから始まる次の行に区切り線を入れてる。
sedの中で使う&(アンパサンド)は一致した文字列の引用を表す。
ある文字列を特定行に挿入する
sed -e "2i hoge" test.txt
sed -e "2a hoge" test.txt
"line2"の行前に挿入
sed -e "/^line2$/i hoge" test.txt
http://d.hatena.ne.jp/rx7/20110310/p1
・viでも置換ができる(編集モードで)
:%s/aaa/bbb/g
aaaに当てはまるものすべてをbbbに置換
:1,3s/bbb/ccc/g
1~3行目のbbbをcccに置換
sedでのアドレス指定
3 3行目
20,$ 20行目から最終行まで
10,5 10行目(2番目の数字が小さい場合)
/^[0-9]/ 先頭が数字の行全て
15,/Z$/ 15行目から最終文字がZで終わる行まで
5,10! 5~10行目以外の行(1~4行目と11~最終行)
行番号を出すには、、
:set nu
行番号を消すには、、
:set nonu
★grep
grep '検索文字列' file
fileから検索文字列を含む行を標準出力に表示する。
-vで含まれない行の意味となる
-nで行番号が出る。
fgrep -f list file
listに含まれる行をfileから標準画面に出力
egrep 'a|b' file
アンド検索。
openssl x509 -noout -text -in cert1.pem | grep -A 2 Subject:
証明書の情報を確認するコマンドの処理結果をパイプでgrepに渡して必要な箇所だけ表示。
-A 2 と指定すると当てはまった行の下の2行も出せる。-B 2 だと上の2行がでる。
# egrep -A 1 "^zone" named.conf|perl -pe 's/{\n//g'|awk '{print $2","$4}'|sed -e '/^,$/d' -e 's/"//g' -e 's/;$//g'|sort
bindの設定ファイルからzone名とtypeをカンマ区切りで抽出
perl -MIO::Socket -e 'my $w = IO::Socket::INET->new(PeerAddr => "whois.jp", PeerPort => 43, Proto => "tcp") or die $!; printf $w "%s\n", shift; print <$w>;' aaaaa.jp/e | grep -i -E '(state|expire)' | grep -i -E -o '([0-9]{4}/[0-9]{2}/[0-9]{2})'
2010/07/31
期限をwhoisで調べる。
★sort
sort -u file
重複する文字列をひとつにして昇順に並び替える
sort -t : -k 2.2n,2.10n file1 > file2
区切り文字を指定して、キーは第2フィールドの2番目の文字から10番目の文字として並べかえる。nで数値として並べかえる。
grep "26/Feb/2007:02" access_log.2007-02-26|awk '{print $2}'|sort|uniq -c|sort -r|more
アクセスログの特定の時間をgrepしてIPをawkで出してuniq -cでカウントしてsort -r で多い順表示
★join
join -a 1 -j1 1 -j2 2 -t : -o 1.1,1.2,1.3,2.2,2.3 txt1 txt2 > file
1番目のファイルは一致しない部分も全て出力、キーのフィールドは1、2番目のファイルのキーのフィールドは2。
区切り文字を指定して、出力するフィールドを指定、引数ファイルを並べて出力ファイルにリダイレクトする。
sortしてからjoinしないと大体失敗する。
★paste
paste -d "," File1 File2
ファイル1とファイル2を区切り文字をカンマとして行を横に結合する。
select結果など完全に同じキーの列がそろうと分かってるときに使うことが多い。
★perl
EID=`nawk -F: '{FS=","; print $11}' $FDIR/DL_OK_$DATE.csv | perl
-pe 's/\n/,/g' | perl -pe 's/,$//g'`
複合的にコマンド処理結果を変数に代入。でもperlでしているのは改行をとって、行末のカンマも取っているだけ。
http://infosys.gsid.nagoya-u.ac.jp/~ohna/perl_lesson/intro2perl/text.html
cut -f1 id_tmp.txt | perl -e 'while(<>) {$word = $_;chomp($word) ;print("^",$word,"\n" ;}' > id.txt
http://www.tohoho-web.com/wwwperl2.htm
http://www.rfs.jp/sb/perl/02/01.html
perl -i -pe 's/\/usr/\#\/usr/g' /etc/cron.daily/slocate.cron
perl -i -pe 's/renice/\#renice/g' /etc/cron.daily/slocate.cron
これは明け方の負荷となるupdatedbをとめたいということ。直接編集せずにperlでsedっている。
サーバの台数が多い場合、直にviしないことで工数削減とオペミス防止に。
perlモジュールのインストール方法は以下のとおりパッケージから入れる方法とcpanからの2種ある。
# yum install --enablerepo=epel perl-DBD-SQLite perl-Time-Piece
# perl -MCPAN -e shell
cpan> install HTML::Template::Expr
つかえるかの確認方法は以下の通りでエラーが出なければよい。
perl -e 'use Time::Piece';
perl -e 'use DBD::SQLite';
perl -e 'use HTML::Template::Expr';
perl -MDBD::mysql -e -1
★scp
・put
scp -Cpr -P [port-num] local-file user@server:/dir
・get
scp -Cpr -P [port-num] user@server:/remote-dir/file /local-dir/
-C = Compress (圧縮)
-p = preserve (ファイルの属性などをそのまま保持)
-r = recursive (再帰的にサブディレクトリのデータも収集する)
★tar
cd taisyou-dir
・圧縮
tar cvf kekka.tar ./taisyou-dir/
-z :gzipを通して処理
-Z :compressを通して処理
-j :bzip2を通して処理
・解凍
tar xvf aaa.tar.gz
・追加
tar rf aaa.tar add.file
・内容表示
tar tf aaa.tar
・1ファイル指定してアーカイブから削除
tar vf aaa.tar --delete file-name
・1ファイル指定して抽出(ディレクトリとファイル名指定する)
tar zxf aaa.tar.gz dir/file
・リストを指定(-T listfile)して固める
time tar -czvf spool_11a.tar.gz -T spool_11a >debug.sp11a.txt
・除外するリストを指定してアーカイブする。
MIRROR_DIR=/data1
EXFL=/opt/bin/exclude.txt
cd $MIRROR_DIR
tar --exclude-from $EXFL -czf $DAILY_BK ./doc/.
・アーカイブしてパイプで渡して圧縮
tar cf - ./mysql/ |bzip2 -c > $BACKUPFILE.bz2
★date
# CDATE=`date '+%Y%m%d.%H%M'`
# DATE=`date '+%Y%m%d'`
# gnu_date -d '1 month ago' +%Y/%m
2007/02
# gnu_date -d '1 month' +%Y/%m
2007/04
gnu_date
Tue Mar 6 20:56:46 JST 2007
スクリプトの中で結果ファイルやログファイルのファイル名を作業日の日付で出したかったりするときによく使う。
solarisだとdateだと前月とか出せません。なのでgnu_dateが入ってればそれを使う。
・UNIX時間を見やすく表示する
# date -d "1970-1-1 GMT +1236038400 second" +%Y%m%d.%H:%M:%S
20090303.09:00:00
# date -d "1970-1-1 JST +1236038400 second" +%Y%m%d.%H:%M:%S
20090303.00:00:00
・指定時刻のUNIX時間(1970/1/1から経過した秒数)を取得する
# date -d "2009-5-24 9:00 JST" +%s
1243123200
・タイムスタンプからローカル時間への変更
# date +%s
1256265645
# awk 'BEGIN{print strftime("%c",1256265645);exit}'
2009年10月23日 11時40分45秒
★find
find / -name aaa.txt -atime 1 -exec rm {} ;
find /export/home -perm -u+x -type f -atime -100 -size +100000k
ファイルを名前で探してアクセスした時間も指定して引数渡して消してしまう。
消すのは検証しまくってからが良さそう。いらないログやバックアップをディスク溢れ防止にcronに組み込んで消すのに便利。
http://www.sixnine.net/roadside/find.html
http://x68000.q-e-d.net/~68user/unix/pickup?find
$ find /hoge/path |tr A-Z a-z |sort |uniq -d
findしたファイルを小文字に統一しuniqで重複ファイルを検索する
# DIRLIST=`grep source /etc/lsyncd.conf.xml|awk -F \" '{print $2}'`
# for i in $DIRLIST;do find $i -type f -o -type d |wc -l;done|awk '{TOTAL+=$1}; END {print TOTAL}'
lsyncdの管理下のファイルとディレクトリ数の合計値を知る(fs.inotify.max_user_watchesと比べる)
find /var/log -name "*log" -type f |xargs ls -l |awk '{total +=$5}; END {print total}'
832128
指定した名称を含むファイルの合計サイズを知る
find /home -size +10000k -exec ls -lh {} \;
指定したサイズ以上のファイルを検索する
# find ./ -name "*.rb" | xargs grep -n node.roles
特定の文字列を含むファイルを検索する(行番号も出す)
★zip
# /usr/local/bin/zip -P hoge -e -j auth_time_left_20090217.zip auth_time_left.20090217.105040.csv
-P **** # password設定
-j # 指定した名前のフォルダに入れる
-e # zipパスワードでEncryptする
zipパスワードをかけてファイルを自動送信するなど。
solarisにもともとついてるzipはパスワードかけれないことが多いので、わざわざ入れる必要がある。
/bin/nice -n 19 /bin/gzip -9 ${LOG_DIR}/access_log.${YESTERDAY}
サイズが大きすぎて負荷が高くなりそうなときに。
nice値で優先度を最低にして、gzipで時間がかかっても圧縮効率を高くする。
★split
split -a 1 -b 1m logfile.log prefix-
ログファイルが肥大化した場合などに使う。
上記の例では、1MB毎に分割(-b 1m)して、プレフィックス文字列の後にアルファベット順にサフィックスを1文字(-a 1)付けて出力する。
★xargs
ls | xargs -i ksh -c 'grep {} data_file | wc -l'
xargsがデータを引き渡すコマンドの中で処理ごとに随時パイプを使いたいが、普通に使うとxargsが全部処理を終了してからパイプに引き渡される。
そこで登場するのがksh。上記のような感じで使えば毎処理ごとにパイプに渡される。中かっこの中身はlsの結果。
★文字化ける時
※Solarisの場合
・Bシェル系なら(プロンプトが$)
LANG=ja
export LANG
・Cシェル系なら(プロンプトが%)
setenv LANG ja
もちろんリモートログインツール(puttyやTeraterm)の文字コードが違ったりフォントが日本語サポートしてなくてもだめなので、設定を調整する。
2007年ころは大体EUC-JPだったが今時のLinuxの文字コードは大体UTF-8。
RedHat系だとcat /etc/sysconfig/i18n
とかすると文字コードが分かる。
またはenv | grep LANG
とか。
bashでつかえるやつ↓
# stty cs8 -istrip -parenb
sttyの引数説明(文字化け対応)
・cs8 偶数パリティを選択
・-istrip 入力文字を7ビットにストリップしない
・-parend パリティの生成と検出を無効にする
★shell
カーネルとコマンド(命令文)の橋渡しをしてくれるもの。シェルから命令文を渡されたカーネルがCPUなどのデバイスに対して処理をさせて結果を返す。
シェルスクリプトは基本的に移植性を考慮してどんな環境でも動くようにBシェルで書くのがいいとされる。移植することを想定しなくてよい場合はbashが便利。
shという一番シンプルなやつ。ボーンシェル。
スクリプトの最初の行に、以下のように書くとそのスクリプトはBシェルで実行可能に。(スクリプトファイルに実行権限があれば。)
#!/bin/sh
☆bash
Cシェルより処理が早くメモリを食う量が比較的少ない。Bシェルの仲間たちのひとつ。
そのためマルチユーザ環境のバッチサーバなどでは推奨される。
-eq 等しい (equal)
-ne 等しくない (not equal)
-lt 小さい (less than)
-le 小さいまたは等しい (less than or equal)
-gt 大きい (greater than)
-ge 大きいまたは等しい (greater than or equal)
-a アンドの意味
-o オアの意味
この他はman test
で確認
移植性を考慮して計算したいならexpr
を使う。
・特殊な変数
シェルスクリプトは引数を利用することができ、bashに初めから用意された特殊な変数を使用し参照することができる。
これらの変数は参照するもので、値を代入することはできない。
変数 | 説明 |
---|---|
$n |
nは数字であり、$0 はシェルスクリプト名、以降$1 、$2 …は第1引数、第2引数…である。第10引数以降は${10} 、${11} …で参照する。"${0##*/}"はディレクトリを取り除いたスクリプト名。 |
$# |
与えられた引数の個数 |
$@ |
$0 以外の全ての引数("$@" のようにダブルクォーテーションで囲んだ場合"$1" "$2" …" のように個別に展開される。) |
$* |
$0 以外の全ての引数("$@" のようにダブルクォーテーションで囲んだ場合"$1 $2 …" のように展開される。) |
$? |
最後に実行したコマンドの終了ステータス |
$! |
最後に実行したバックグラウンドコマンドのPID |
$$ |
シェルのPID |
$- |
現在のオプションフラグ |
参考:
if [ $# -lt 2 ]
then
echo "引数が足りません。"
echo "usage: $0 user_id enduser_id"
exit 1
else
:
fi
この場合は、引数が2個未満ならecho
でエラーと使い方表示出して終了、そうでなければ続ける。
if
で条件分岐に使う[]
はtest
コマンドとイコール。
他にも色々な条件指定が可能。
http://www.linux.or.jp/JM/html/gnumaniak/man1/test.1.html
・ループ処理
・while loop 参考
DATE=20080809
D=09
T1=00
T2=01
T3=02
Y=2008
M=Aug
HOST=`uname -n`
cd /usr/local/apache/logs
i='0'
while [ $i -le 9 ]
do
zgrep -c "${D}/${M}/${Y}:${T1}:0${i}" ${HOST}.access_log.${DATE}.gz >> ${HOST}.${T1}min${DATE}.log
zgrep -c "${D}/${M}/${Y}:${T2}:0${i}" ${HOST}.access_log.${DATE}.gz >> ${HOST}.${T2}min${DATE}.log
zgrep -c "${D}/${M}/${Y}:${T3}:0${i}" ${HOST}.access_log.${DATE}.gz >> ${HOST}.${T3}min${DATE}.log
i=`expr $i + 1`
done
i='10'
while [ $i -le 59 ]
do
zgrep -c "${D}/${M}/${Y}:${T1}:${i}" ${HOST}.access_log.${DATE}.gz >> ${HOST}.${T1}min${DATE}.log
zgrep -c "${D}/${M}/${Y}:${T2}:${i}" ${HOST}.access_log.${DATE}.gz >> ${HOST}.${T2}min${DATE}.log
zgrep -c "${D}/${M}/${Y}:${T3}:${i}" ${HOST}.access_log.${DATE}.gz >> ${HOST}.${T3}min${DATE}.log
i=`expr $i + 1`
done
※分毎にアクセスログをカウントして時間毎のファイルに出力している
・for loop 参考
list="a b c"
for i in $list
do
echo ${i}
done
・for文を入れ子(nest)にしてみる
# for i in aaa bbb ccc; do echo "$i"; for a in 1 2 3;do echo "$a" ;done; done
aaa
1
2
3
bbb
1
2
3
ccc
1
2
3
例:heartbeatのパスをとおす(様々なタイプと権限のファイルが混在するリンク元から一気にシンボリックリンク貼りたい場合)
LIST=(
`find /usr/lib64/heartbeat -maxdepth 1 -type f -perm +1`
)
for i in ${LIST[@]}
do
ln -s ${i} /usr/local/bin/
done
一行で何かしたい場合はセミコロンで区切るなど。
for i in `seq 2 9`;do cp -p ifcfg-eth0:1 ifcfg-eth0:${i};sed -i "s/0:1/0:${i}/g" ifcfg-eth0:${i};done
仮想NICをseqで渡して一気につくりDEVICEを置換してる。
・コントロールキー
キー | stty名 | 機能 |
---|---|---|
CTRL-C | intr | 現在のコマンドを中止 |
CTRL-D | eof | 入力を終了 |
CTRL-| quit | CTRL-Cが未成功時現在のコマンドを中止 | |
CTRL-S | stop | 画面への出力を停止 |
CTRL-Q | -- | 画面への出力を開始 |
DELorCTRL | -? | erase 最後の文字を削除 |
CTRL-U | kill | コマンドライン全体を削除 |
CTRL-Z | susp | 現在のコマンドを一時停止 |
・シェルのリダイレクト関連参考頁
http://sonic64.com/2004-03-28.html
http://e-words.jp/w/E38395E382A1E382A4E383ABE38387E382A3E382B9E382AFE383AAE38397E382BF.html
http://cai.cs.shinshu-u.ac.jp/sugsi/Lecture/HowToUnix/2-1.html
・正規表現
よく使うメタ文字のメモ。
. 改行を除く任意の1文字
* 0回以上の繰り返し
+ 1回以上の繰り返し
? 0回または1回
^ 先頭
$ 末尾
正規表現関連参考頁
http://www.sixnine.net/regexp/regexp3.html
http://www.kt.rim.or.jp/~kbk/regex/regex.html
・その他
うっかり実行したあとのコマンドをバックグラウンドに渡す、、ctrl+z
のちbg
と打つ。