findコマンドで、そんな深い階層まで調べなくていいよって時に使う。
自分はカレントディレクトリのみでいい時に使うことが多そう。
- カレントディレクトリのみでファイル名がgzで終わるやつ
 1find -maxdepth 1 -a -xtype f -a -name "*.gz"
 -maxdepth n で階層を指定してあげればよい。1ならカレントディレクトリのみ
スクリプトで配下のディレクトリにファイルをmvして、移動したファイルが次回のスクリプトで対象になってほしくない時なんかに使うと思う。
前の記事で、disownの素晴らしさを紹介したが、基本的に標準出力・標準エラーを諦めることになる。
調子の悪いHDDの丸ごとコピーとかだと、標準エラーを後で見たいので、なんとかならないかネット検索したところ、
gdbで接続して、dup2で標準出力・標準エラーをファイルに繋ぐなんて荒業を紹介している人がいた。
dup2なんてCプログラマじゃなきゃ使おうとも思わんな。
流れとしては、
うーん。絶対忘れる。
以下、サンプル。実際はcpとかでやると思うが今回は、標準出力と標準エラーが分かりやすいようにしている。
標準出力にはdateの結果、標準エラーにはerrorを5秒間隔で。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | $ bash -c 'while /bin/true ; do date ; echo error >&2;sleep 5; done ' 2014年 8月 12日 火曜日 12:16:25 JST error Ctrl-z # 一旦止める。 $ bg # バックグラウンドにする。 $ disown %1 # ここまででプロセスの準備OK。出力があるので、一度ログアウトして入り直した方がいいかも。 $ ps axfwww |grep while 8458 ? S 0:00 \_ bash -c while /bin/true ; do date ; echo error >&2;sleep 5; done # プロセスID確認 今回は、8458 $ touch /tmp/std{out,err} # ファイルを作る # # gdbで繋ぐ。ubuntuだと設定にもよるがsudoが必要。 # $ sudo gdb -p 8458 ###### snip ######## (gdb) p dup2(open("/tmp/stdout",1),1) # 標準出力を繋ぐ (gdb) p dup2(open("/tmp/stderr",1),2) # 標準エラーを繋ぐ (gdb) detach # デタッチ (gdb) quit # gdbを終了 # 確認する $ tail /tmp/stdout 2014年 8月 12日 火曜日 12:25:08 JST 2014年 8月 12日 火曜日 12:25:13 JST 2014年 8月 12日 火曜日 12:25:40 JST $ tail /tmp/stderr error error error | 
うーん。非常にメンドイ。なるべくnohupを使いましょう。それか日常的にscreenを使いましょうってことですね。
ただ、考え方は非常に面白いので、覚えておくのはいいと思う。
軽い気持ちで実行したコマンドが、なかなか終わらなくて、あー。もー。帰りたいのに終わるまで帰れない。
なんて経験があったりする。ただこの disown ってコマンドを覚えておけば、そんなことを気にしないで実行したまま家に帰ることが出来る。
たぶんbash限定かもしれないけど、自分bashしか使わないので。。。
具体的には、
Ctrl-z でプロセスを一旦止めて、
bg でバックグラウンドプロセスにして。
って感じ。
ただこのままログアウトしても大丈夫なプロセスもあったりするのだが、止まるやつは止まる。
そこで、 disown %1 を実行してあげる。(%1はjob id jobsコマンドで確認出来る)
これでログアウトしても止まらないはずなので、安心して帰れる。
以下サンプル(cpの大量コピーとかがよくあるかと)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $ cp -av /media/usb-hdd my-bkup/ Ctrl-z # ここで一旦止める。 $ bg # バックグラウンドにする。 $ jobs [1]+ 実行中 cp -av /media/usb-hdd my-bkup/ & # job idを確認。ここでは%1 $ disown %1 $ jobs # 自分のjobから消えてればOK | 
こんな感じ。標準出力するプログラムだと、入力が大変だが、めげずに実行する。
ログアウトすると、標準出力、標準エラーは保存できないので、そこは諦めるか別の方法。
最初から、時間がかかるのがわかっているなら、 nohup を使ったほうが良い。標準出力もファイルに保存されるので。
nohupの記事も過去にちょろっと書いた。
diffでファイルの比較とかやってると、実行するコマンドの結果(標準出力)を元に比較出来ないのかなと悩むことがある。
一度ファイルに落としてからdiffすればいいので、特に調べてなかったが、ちょいと調べたらあっさり見つかった。
コマンドの標準出力を比較する場合。
| 1 | $ diff <( command1 ) <( command2) | 
うわ。めっちゃ簡単。bashだけらしいけど、bash以外使った事ないから充分。
<(の間にはスペースは入れてはだめ。
コマンドの標準出力とファイルを比較する場合。
| 1 | $ diff <( command1 ) file1 | 
diffに限らず
| 1 | <( command ) | 
こいつは、いろんなところで使えそう。
無知は罪ですな。
なかなか便利だけど忘れてしまうブレース展開
この記事でもちょっと触れたが、今回は違う使い方。
Linuxのサーバを管理していると、コンフィグを変更する前に、バックアップファイルを作ったりすると思う。
例)
| 1 | # cp -ip /etc/hosts /etc/hosts.bk | 
これもブレース展開でやれば、タイプ量も少なくて経済的
例)
| 1 | # cp -ip /etc/hosts{,.bk} | 
うーん。便利。
普段Linuxをメインで使っていると、bashで、forとかwhileループをバシバシ使って処理することがあると思う。
直ぐ終わる処理だと、特に気にしないのだが、大量のデカイファイルをコピーするなど
時間のかかる処理だと、バックグラウンドで実行したい時があるが、普通にnohup使うと
エラーになって使えない。
| 1 | for i in `ls -1Sh |head -30 `; do mv -i $i /tmp; done | 
単純に頭にnohupを付けて行末に&だと上手くいかず
以下のようにしたら上手く言った。
| 1 | nohup bash -c 'for i in `ls -1Sh |head -30 `; do mv -i "$i" /tmp; done' & | 
と言った感じ
前にシェルスクリプトでアルファベット一覧を出力する方法を書いたが、今日もっと驚異的に簡単な方法を知ってしまった。
ブレース展開というらしい。
| 1 2 3 4 5 | $ echo {a..z} a b c d e f g h i j k l m n o p q r s t u v w x y z $ echo {A..Z} A B C D E F G H I J K L M N O P Q R S T U V W X Y Z | 
これだけ。前回のは何だったのかと悲しくなるくらい簡単だった。
このブレース展開、(,)カンマ区切りだと見たことある気がするけど、(.)ピリオド2つで範囲指定出来るとは驚き。
しかも隣接する文字がある場合は、そっちも展開してくれるのでIPアドレスの範囲指定なんかでも超便利。
| 1 2 | $ echo 192.168.{0..5}.255 192.168.0.255 192.168.1.255 192.168.2.255 192.168.3.255 192.168.4.255 192.168.5.255 | 
うーん。無知って罪ですね。
シェルスクリプトを書いていると、エラー処理を書くのが面倒で、とりあえずbashをeオプションで起動しておけばいいや程度に思っていたりします。シェルスクリプト中のどこかでエラーが出ればスクリプト自体を終了してくれるので何かと便利なんですが、途中無視できる程度のエラー処理で止まって困ることもあるので、そこを何とか無視する方法を調べました。まーmanに書いてあったんでちょっと読めば気付くんでしょうが自分は結構時間かかりました。
-e 単純なコマンド (前述の シェルの文法セクションを参照) が 0 でないステータスで終了した場合、即座に終了します。ただし 失敗したコマンドが until または while ループの一部である、 if 文の一部である、 && または ││ リストの一部である、コマンドの返り値が ! で反転されている、のいずれかの場合にはシェルは終了しません。
上の条件に当てはめてしまえばいいだけです。
サンプルとして、以下のようなスクリプト。
| 1 2 3 4 5 6 7 8 9 | #!/bin/bash -e echo "最初のecho" /bin/false || echo エラーでも続行 echo "多分ここで終わる" /bin/false echo "これは出ないはず" | 
最初のfalseでは、止まらず次のfalseで止まって、最後のechoは処理されないはずです。