木曜日, 11月 29, 2007

Geekなぺーじ : 10のUNIX小技

Geekなぺーじ : 10のUNIX小技

①:複数階層のフォルダを一回で作成する。

[root@localhost ~]# mkdir -p a/b/c

[root@localhost ~]# mkdir -p a/{lib,src/doc/{html,pdf,txt}}

mkdirに-pオプションがない場合、mkdirhierを使うことが出来るらしい。
と書いてあったけど、RadhatAS4ではだめだった。
[root@localhost ~]# mkdirhier -p a/{lib,src/doc/{html,pdf,txt}}  -- NG

②:tarの解凍先を指定する。

[root@localhost ~]# tar xfv a.tar -C /tmp/a/b

③:コマンドを演算子で繋げる

一つ目のコマンドが成功した(return 0)場合にだけ実行
[root@localhost ~]# cd tmp/a/b/c && tar xvf ~/archive.tar

一つ目のコマンドが失敗した(return 0以外)場合にだけ実行
[root@localhost ~]# cd tmp/a/b/c || mkdir -p tmp/a/b/c
[root@localhost ~]# cd tmp/a/b || mkdir -p tmp/a/b && tar xvf -C tmp/a/b ~/a.tar

④:変数と「"」の組み合わせは慎重に

[root@localhost ~]#
[root@localhost ~]# ls tmp/
a b
[root@localhost ~]# VAR="tmp/*"
[root@localhost ~]# echo $VAR
tmp/a tmp/b
[root@localhost ~]# echo "$VAR"
tmp/*
[root@localhost ~]# echo $VARa

[root@localhost ~]# echo "$VARa"

[root@localhost ~]# echo "${VAR}a"
tmp/*a
[root@localhost ~]# echo ${VAR}a
tmp/a
[root@localhost ~]#

⑤:長い入力にはエスケープシーケンスを利用

[root@localhost ~]# cd tmp/a/b/c || \
> mkdir -p tmp/a/b/c && \
> tar xvf -C tmp/a/b/c ~/archive.tar

でも
[root@localhost ~]# cd tmp/a/b/c \
はNGだった。

⑥:コマンドをグループ分けする

[root@localhost ~]# ( cd tmp/a/b/c/ || mkdir -p tmp/a/b/c && \
> VAR=$PWD; cd ~; tar xvf -C $VAR archive.tar ) \
> | mailx admin -S "Archive contents"

<>
[root@localhost ~]# { cp ${VAR}a . && chown -R guest.guest a && \
> tar cvf newarchive.tar a; } | mailx admin -S "New archive"

「{}」の前後にスペースが入るように注意しましょう。
スペースを入れないと正しく動作しないかも知れません。
また、「}」の前に来る最後のコマンドの後に「;」を入れる。

⑦:xargsをfind以外と組み合わせる

[root@localhost ~]# find 何か どこかへのパス | \
> xargs ファイル名を使う何らかのコマンド

$ xargs
a
b
c
コントロールキー+p
a b c

ファイル名を出力する他のコマンドと組み合わせる事も可能です。

$ ls | xargs
December_Report.pdf README a archive.tar mkdirhier.sh
$ ls | xargs file
December_Report.pdf: PDF document, version 1.3
README: ASCII text
a: directory
archive.tar: POSIX tar archive
mkdirhier.sh: Bourne shell script text executable

複数行を一行にまとめる事も出来ます。


$ ls -l | xargs
-rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf -rw-r--r-- 1 \
root root 238 Dec 03 08:19 README drwxr-xr-x 38 joe joe 354082 Nov 02 \
16:07 a -rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar -rwxr-xr-x 1 \
joe joe 3239 Sep 30 12:40 mkdirhier.sh

xargs利用上の注意

「_(アンダースコア、下棒)」はEOFとして扱われます。
そのため、その文字がxargsに渡されると、
それ以降の項目は無視されてしまいます。
この問題を回避するには-eオプションを利用してください。

⑧:grepに行数をカウントさせる

wc -l と組み合わせるのではなく、grep の-cオプションを使った方が行数の計算は速いです。

$ time grep PATTERN longfile.txt | wc -l
2811

real 0m0.097s
user 0m0.006s
sys 0m0.032s
$ time grep -c PATTERN longfile.txt
2811

real 0m0.013s
user 0m0.006s
sys 0m0.005s

grepがカウントすべきではないとき

-cオプションは、マッチした行数のみをカウントします。
-oオプションは、マッチしたパターン自体を出力します。
単一行にマッチするパターンが複数回登場する時などには、
-oオプションにより標準出力に出される行数と、
-c が行った結果のカウント数が異なってしまいます。
そのような場合には、wc -l を使いましょう。

grep -o PATTERN longfile.txt | wc -l

⑨:パターンマッチは行全体ではなくフィールドで

grepなどで行全体をマッチするのではなく、
awkで特定のフィールドを指定してパターンマッチをすべきです。

grepで行全体をマッチさせてしまうと、意図しないものも結果に入ってしまうことがあります。
例えば、ファイル更新日が12月のものを探している時に、
1月に更新したDecemberReport.pdfが結果に入ってしまう場合があります。

悪い例

ls -l | grep Dec
-rw-r--r-- 7 joe joe 12043 Jan 27 20:36 December_Report.pdf
-rw-r--r-- 1 root root 238 Dec 03 08:19 README
-rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar
良い例

ls -l | awk '$6 == "Dec"'
-rw-r--r-- 3 joe joe 5096 Dec 14 14:26 archive.tar
-rw-r--r-- 1 root root 238 Dec 03 08:19 README

⑩:無駄なcatとパイプは行わない

grepなどのコマンドを使う時に、catをパイプで繋げてgrepの標準入力に流し込むのは無駄です。
grepなどの大抵のコマンドには、ファイル名をオプションとして渡せる機能があります。
以下に速度の比較を示します。


$ time cat longfile.txt | grep PATTERN
2811

real 0m0.015s
user 0m0.003s
sys 0m0.013s

$ time grep PATTERN longfile.txt
2811

real 0m0.010s
user 0m0.006s
sys 0m0.004s

---------------------------
いろいろ出来ますね。勉強になりました。