Linuxコマンド

vi(vim)

Linuxをおぼえるときは、コマンドもそうだけど、vi(vim)の使い方をおぼえるのが大事な気がする。
サーバやらツールのやらの設定ファイルの編集がスムーズにできないと、それだけでいやになってしまうので。

自分は、まずは、Windows版のvimで使い方をおぼえた。5時間×2日で、自転車の練習のようにおぼえた。正直、これだけではまだまだ慣れるまではいかないのだけど、手は動くようになる。メモをつくりながら、便利な操作をどんどん調べて、使っていくとよいとおもう。

基本の操作
  • 行番号を表示する。
    • :set number
  • 指定した行へ移動する。
    • 最後の行へ
      • G
    • 10行目へ
      • 10G


何単位で何をするのか?を意識することが必要。
単位と処理を組み合わせる。

  • 文字単位の処理
    • 現在のカーソル位置から6文字削除右へ
      • 6dl
  • 単語単位の処理
    • 現在のカーソル位置から9単語移動右へ
      • 9w
  • 行単位の処理
    • 現在のカーソルのある行をヤンク(コピー)
      • :yy
    • 10行目をヤンク(コピー)
      • :10y
    • 21行目から30行目をヤンク(コピー)
      • :21,30y
      • ヤンクしたものを貼り付けるは、pまたはP
    • 31行目から40行目をを置換
      • :31,40s/abc/efg/g
    • 41行目から最後の行まで削除
      • :41,$d
  • 全行の処理
    • 全行を置換
      • 全行を表す記号は%
      • :%s/abc/efg/g
      • :%s;/pqr;/stu;g(置換する単語に/を含む場合は、/ではない単語で区切る。ここでは、;)
文字コード指定
ファイルを開くとき
vim "+e ++enc=文字コード ファイル名"
ファイルを開いているとき
:e ++enc=文字コード
参考

Vim — KaoriYa
Windows版を配布してくれている。vimrcの設定も参考になる。

Vim 基本操作まとめ - Archiva

http://vimeo.com/22709519



ファイル

ls
  • ls -ltr
    • タイムスタンプの逆順でソートして表示
    • このオプションだとファイルが多いディレクトリで、今、更新したファイルが下に表示されるので、更新したファイルを確認しやすい。
  • ls -l --time-style=+'%Y-%m-%d %H:%M:%S'
    • タイムスタンプ表示のフォーマットを指定
basename
eiichi@ubuntu-desktop:~/test$ basename /home/eiichi/test/a.txt 
a.txt

bashだったら、シェルスクリプト中で

FILE_NAME=$(basename $0)
dirname


eiichi@ubuntu-desktop:~/test$ dirname /home/eiichi/test/a.txt
/home/eiichi/test

bashだったら、シェルスクリプト中で

DIR_PATH=$(dirname $0)

ただし、シェルスクリプトの呼び出し方によって、$0の値は変わるので注意

ためしに、作業ディレクトリ/bin/get-path.shを作成する。

#!/bin/bash

echo $0

実行すると、

  • 相対パスで実行
  • フルパスで実行
  • コマンドパスに通してで実行

で、$0の値は変わる。

eiichi@ubuntu-desktop:~/Programming/shellscripts$ bin/get-path.sh 
bin/get-path.sh
eiichi@ubuntu-desktop:~/Programming/shellscripts$ $(pwd)/bin/get-path.sh 
/home/eiichi/Programming/shellscripts/bin/get-path.sh
eiichi@ubuntu-desktop:~/Programming/shellscripts$ PATH=$PATH:$(pwd)/bin
eiichi@ubuntu-desktop:~/Programming/shellscripts$ get-path.sh 
/home/eiichi/Programming/shellscripts/bin/get-path.sh
readlink

フルパスを取得するためには、

readlink -f ファイルパス

コマンドを検索

which

ファイルを検索

find

ファイルの検索ではとても便利。検索条件を指定するためのオプションが豊富。重い処理になることもあるので、本番サーバや大勢がつかっているサーバで実行するときは注意。

  • find . -name 検索ファイル名 -print
    • 名前で検索
  • find . -type d -print
  • find . -size +NNNN -print
    • ファイルサイズがNNNN以上

単なる検索だけでなく、ファイルやディレクトリを抽出して、それらに対してコマンドを適用するのがとても便利。
grepと組み合わせると、さらにファイル名を正規表現で抽出できる。
xargsと組み合わせると、検索したファイルに対して、削除など、なんらかの処理を実行できる。xargsの%は、置換文字列

  • find /home/eiichi/ -name '*.txt' | grep -E 'shellscripts' | xargs -I% cp % backup/
  • find . -maxdepth 1 -type d -print | xargs -I% du -s % | sort -k1 -n
locate

高速な検索ができる。
ただし、事前に
updatedb
の実行が必要。

ファイルの中の文字列を検索

grep
  • grep 検索文字列 ファイルパス
  • grep -n 検索文字列 ファイルパス
    • 行番号表示
  • grep -o 検索文字列 ファイルパス
    • マッチした文字列を含む行じゃなくて、マッチした文字列のみを表示
  • grep -v 検索文字列 ファイルパス
    • 検索文字列を含まない行にヒット
  • grep -r 検索文字列 .
    • 検索対象ファイルを絞り込んだ上で、ファイルの内容について、grepしたいなら、以下のようなコマンドかな
      • find . -type f -print | xargs grep 検索文字列
  • grep -E

ファイルを圧縮および解凍

tar

圧縮

$ ls -la aaaa/bbbb/cccc/
合計 8
drwxr-xr-x 2 eiichi eiichi 4096 2012-10-25 23:54 .
drwxr-xr-x 3 eiichi eiichi 4096 2012-10-25 23:53 ..
-rw-r--r-- 1 eiichi eiichi    0 2012-10-25 23:54 xxxx.txt
-rw-r--r-- 1 eiichi eiichi    0 2012-10-25 23:54 yyyy.txt

$ tar cvfz cccc.tar.gz -C aaaa/bbbb/cccc .
./
./yyyy.txt
./xxxx.txt
$ tar cvfz cccc.tar.gz -C aaaa/bbbb cccc
cccc/
cccc/yyyy.txt
cccc/xxxx.txt

展開

$ tar xvfz cccc.tar.gz 
cccc/
cccc/yyyy.txt
cccc/xxxx.txt
$ ls -la cccc
合計 8
drwxr-xr-x  2 eiichi eiichi 4096 2012-10-25 23:54 .
drwxr-xr-x 17 eiichi eiichi 4096 2012-10-25 23:58 ..
-rw-r--r--  1 eiichi eiichi    0 2012-10-25 23:54 xxxx.txt
-rw-r--r--  1 eiichi eiichi    0 2012-10-25 23:54 yyyy.txt
$ tar xvfz cccc.tar.gz -C eeee/ffff/
cccc/
cccc/yyyy.txt
cccc/xxxx.txt
$ ls -la eeee/ffff/cccc/
合計 8
drwxr-xr-x 2 eiichi eiichi 4096 2012-10-25 23:54 .
drwxr-xr-x 3 eiichi eiichi 4096 2012-10-26 00:00 ..
-rw-r--r-- 1 eiichi eiichi    0 2012-10-25 23:54 xxxx.txt
-rw-r--r-- 1 eiichi eiichi    0 2012-10-25 23:54 yyyy.txt

ドキュメントを検索

ファイル名の一括変更

for f in $(ls | grep 20110901); do mv $f $(echo $f | sed 's/20110901/20110831/'); done

rename 's/20110831/20110830/' *

文字列の処理

sed


置換して、ファイルの内容はそのまま
sed -e 's/aaaa/bbbb/g' ファイルパス

置換して、ファイルの内容を上書き
sed -i 's/aaaa/bbbb/g' ファイルパス

後方参照

$ echo '123abc456' 
123abc456
$ echo '123abc456' | sed -e 's/\([0-9]\+\)\(.[a-z]\+\)\([0-9]\+\)/\1 \3/g'
123 456
perl

クォーテーションを、後方参照で取り除いてみる

$ echo "'a'" 
'a'
$ echo "'a'" | perl -i -p -e "s/'(.+)'/\$1/g"
a
$ echo '"a"' 
"a"
$ echo '"a"' | perl -i -p -e 's/"(.+)"/$1/g'
a
cut
  • echo 'aaaa:bbbb:cccc' | cut -d':' -f1,3
awk

CSVファイルの読み込み

cat awk-test.csv 
11,12,13,14
21,22,23,24
31,32,33,34

awk  -F',' '{print $2":"$3}' awk-test.csv 
12:13
22:23
32:33


10個おきに改行する。awkでは、NRは行番号を表している。

seq 1 20 | awk 'NR % 10 == 0 {printf("%s\n", $0)} NR % 10 != 0 {printf("%s ", $0)}'
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20

シェルスクリプト中で、シェル変数をわたす

with-awk.sh

#!/bin/bash

LEFT_DECO="****++++"
RIGHT_DECO="+++++****"

awk -v LD="$LEFT_DECO" -v RD="$RIGHT_DECO" '{print LD" "$0" "RD}' test.txt
test.txt

aaaaaaa
bbbbbbb
ccccccc
ddddddd
eiichi@ubuntu-desktop:~/Programming/shellscripts$ ./with-awk.sh 
****++++ aaaaaaa +++++****
****++++ bbbbbbb +++++****
****++++ ccccccc +++++****
****++++ ddddddd +++++****


awkの関数もあるよ

sub 最初に見つかった文字列だけ置換

 echo "AaAa BBBB CCCC" | awk -F' ' '{x=$1;sub("a", "A", x);printf("%s-%s-%s\n", x, $2, $3)}'
AAAa-BBBB-CCCC


gsub 正規表現で、見つかった文字列を全部置換

echo "AaAa BBBB CCCC" | awk -F' ' '{x=$1;gsub("a", "A", x);printf("%s-%s-%s\n", x, $2, $3)}'
AAAA-BBBB-CCCC

何かの数を数える

wc
  • 行数を数える。
    • wc -l
  • 同じ行にabcという単語が含まれている場合は、まずgrep -oをするとよい
    • grep -oE 'abc' | wc -l
  • 拡張子がtxtのファイル数の数だったら、
    • ls *.txt | wc -l

ソート


eiichi@ubuntu-desktop:~$ seq 1 15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

-rで逆順にする。


eiichi@ubuntu-desktop:~$ seq 1 15 | sort -r
9
8
7
6
5
4
3
2
15
14
13
12
11
10
1

たしかにソートされてるんだけど、期待と違う。
-nオプションをつける


eiichi@ubuntu-desktop:~$ seq 1 15 | sort -nr
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1

期待通りになった。

tsvファイルなどで、特定の列をソートすることもできる。
タブがデリミタになっている場合


sort -t$'\t' -k2

日時

date
$ date
2012年 10月 25日 木曜日 00:01:24 JST
$ date +'%Y-%m-%d %H:%M:%S'
2012-10-25 00:01:32
$ date -d '2013-01-02 12:34:56' +'%Y%m%d%H%M%S'
20130102123456
$ date -d '2013-01-02 12:34:56 5 days' +'%Y%m%d%H%M%S'
20130107123456
$ date -d '2013-01-02 12:34:56 2 months ago' +'%Y%m%d%H%M%S'
20121102123456

日時を比較したいときは、エポックからの秒数になおす

$ A=$(date +'%s')
$ B=$(date +'%s')
$ echo $A
1351091129
$ echo $B
1351091135
$ test $A -lt $B 
$ echo $?
0
$ test $A -eq $B 
$ echo $?
1
$ test $A -gt $B 
$ echo $?
1

日時を比較したいとき、bashであれば、'<'や'>'も使える。
日時というか文字列の比較になる。

$ test '2014-01-01' '<' '2014-01-01'
$ echo $?
1
$ test '2014-01-01' '<' '2014-01-02'
$ echo $?
0
日付を連番で出力 while
date-seq-a.sh 

#!/bin/bash

START_DATE='2014-01-01'
END_DATE='2014-01-10'
CURRENT_DATE=$START_DATE

COUNT=0
while [ $CURRENT_DATE '<' $END_DATE -o $CURRENT_DATE = $END_DATE ]
do
    echo $CURRENT_DATE

    COUNT=$(($COUNT + 1))
    CURRENT_DATE=$(date -d "$START_DATE $COUNT days" +'%Y-%m-%d')
done
$ ./date-seq-a.sh 
2014-01-01
2014-01-02
2014-01-03
2014-01-04
2014-01-05
2014-01-06
2014-01-07
2014-01-08
2014-01-09
2014-01-10
日付を連番で出力 seq
date-seq-b.sh 

#!/bin/bash

START_DATE='2014-01-01'
END_DATE='2014-01-10'

START_EPOCH_TIME=$(date -d $START_DATE +'%s')
END_EPOCH_TIME=$(date -d $END_DATE +'%s')

COUNT=$(((END_EPOCH_TIME - START_EPOCH_TIME) / 86400))

seq 0 $COUNT | xargs -I{} date -d "$START_DATE {} days" +'%Y-%m-%d' 
$ ./date-seq-b.sh 
2014-01-01
2014-01-02
2014-01-03
2014-01-04
2014-01-05
2014-01-06
2014-01-07
2014-01-08
2014-01-09
2014-01-10

フォーマット

printf

printfが使えるようだ。


eiichi@ubuntu-desktop:~$ seq 1 4
1
2
3
4


eiichi@ubuntu-desktop:~$ seq 1 4 | xargs printf %02d\\n
01
02
03
04

コマンドを補助するコマンド

xargs

このページのほかのコマンドの例でもxargsをちらほらつかっている。

find . -type f -print0 | xargs -0 mv -t to-dir
time

あるコマンドの処理時間を計測しつつ、そのコマンドを実行する。

$ time wget http://www.google.co.jp
--2014-02-15 03:14:10--  http://www.google.co.jp/
www.google.co.jp (www.google.co.jp) をDNSに問いあわせています... 173.194.126.183, 173.194.126.191, 173.194.126.184, ...
www.google.co.jp (www.google.co.jp)|173.194.126.183|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 特定できません [text/html]
`index.html.2' に保存中

    [ <=>                                                                                            ] 11,274      --.-K/s   時間 0.001s

2014-02-15 03:14:10 (11.0 MB/s) - `index.html.2' へ保存終了 [11274]

real	0m0.148s
user	0m0.027s
sys	0m0.055s

文字コード

  • file ファイルパス
    • 改行コードが、LFならば、なにも表示しない。
    • 改行コードが、CR+LFならば、そのように表示してくれる。
  • nkf -g ファイルパス
特に、改行コード
  • od -c
    • 改行コード用じゃないんだけど、改行コードも見やすく表示される

文字コード変換

nkf

ユーザ管理

useradd
usermod
  • usermod -g グループ名 ユーザ名
    • デフォルトのグループを変更
  • usermod -G グループ名 ユーザ名
    • グループにこのユーザを追加

cat /etc/group
で確認

userdel

指定したタイミングで実行

cron
  • いつ、どのコマンドを実行したいのか設定ファイルに記述して利用する
  • cron本体のプロセスは、root権限で実行されるが、個々の処理は、該当ユーザの権限で実行される。
    • cronの設定ファイル自体がユーザごとに用意される。
  • 設定ファイルの編集
    • 実行したいユーザになって、以下のコマンドで、設定ファイルを編集する。
      • crontab -e
    • 設定ファイルには、PATHのような、変数も記述できる。
    • デフォルトの設定ファイルは以下なのか?
      • /etc/crontab
  • 前の処理が処理中でも、次の処理が実行されてしまうので注意
    • たとえば、10分おきに、あるバッチ処理を実行する。このとき、このバッチ実行に15分かかったとする。この場合、前のバッチ処理を継続したまま、次のバッチ処理を実行となるので、処理が重ならないようにするための工夫が必要
      • よくあるのは、ロックファイルか?
      • cron使わないで、バッチ処理が正常終了したときだけ、atコマンドで、次回実行の分だけを設定とかもありなのかもしれない。でもこれだと、初回実行とか異常終了したときの対応がめんどう。

cron以外にも、同様のソフトがある。

ジョブ管理システム
ジョブ管理システム - Wikipedia
たくさんのジョブを管理する場合は、ジョブとジョブの実行の順番の配慮など、cronではきびしいので、こういうミドルウェアもよく使われている。

Java
http://www.quartz-scheduler.org/documentation/quartz-2.1.x/quick-start

at
watch

watch -n 1 -x uptime
watch -n 1 -dc uptime

uptimeコマンドを1秒おきに実行

  • dcだと、差分をハイライトしてくれるので、変化したことがわかりやすい。

ディスク

df
du

du -h

ハードやOS

/proc配下を見る

cd /proc

#CPU
cat cpuinfo

#OS
cat version

状態確認

sysstatパッケージをあらかじめ導入しておく。

たとえば、

sudo apt-get install sysstat

システム関連のデータなので、
/proc
の値を直接見ることもできるが、コマンドをたたいたほうが、利便性がよい。

ps
top
free
vmstat
iostat
sar