トップページunix
1001コメント289KB

シェルスクリプト総合 その20

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。2012/06/08(金) 00:35:51.19
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。

□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
 bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
 Linuxユーザは/bin/shの正体がbashなので特に注意。
 FreeBSDユーザは/bin/shの正体がashなので注意。
 v7 shに一番近くて、現役のshは、OpenSolaris由来のheirloom sh。
  http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sh/
  http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
 (理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
 manや参考リンクを見ましょう。
 aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
 正規表現の話題はスレ違い(正規表現スレへ)

□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
 RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。

前スレ
シェルスクリプト総合 その19
http://toro.2ch.net/test/read.cgi/unix/1323515200/
0009名無しさん@お腹いっぱい。2012/06/08(金) 07:58:45.93
>>6
つまり座学で基礎理論を学んでから出直せってこと?
0010名無しさん@お腹いっぱい。2012/06/08(金) 09:38:32.41
>>2
衣服(shell)の重ね着(layered)のことだろ。
登山なんかでは速乾性の下着から防水防風透湿のジャケットまで
機能の異なる薄手のシェルを何枚も重ねて着るのが常識。
0011名無しさん@お腹いっぱい。2012/06/08(金) 09:49:49.84
>>2 shl BSDのジョブコントロールのSysV版
http://docstore.mik.ua/orelly/unix/unixnut/c02_191.htm
http://www.unix.com/man-page/All/1/shl/
http://cai.cs.shinshu-u.ac.jp/sugsi/Lecture/HowToUnix/3-1.html
0012名無しさん@お腹いっぱい。2012/06/08(金) 09:55:28.15
>>8が端的に説明できてる。ただscreen知らないとわからない。
0013名無しさん@お腹いっぱい。2012/06/08(金) 16:51:20.05
シェルといえば、ガソスタだろ?または、>>10だな。常識。
... なる程、shlか。知らなかった。sh -kといい、まさにトリビア級。すごい。
0014 忍法帖【Lv=40,xxxPT】 2012/06/09(土) 13:44:28.09
grepで取り出した10行のうちの2行目を取り出したいのですが、
何か簡便な方法はありませんか?
0015名無しさん@お腹いっぱい。2012/06/09(土) 13:48:39.99
sed -n 2p
0016名無しさん@お腹いっぱい。2012/06/09(土) 13:48:53.77
>>14
素人は grep 〜 | head -n 2 | tail -n 1 なんてするところだろうな

Cで2行目取り出すツールを書くのが最速
fgetc()とかで何とかなる
0017名無しさん@お腹いっぱい。2012/06/09(土) 13:53:34.23
>>14
grep -A1
でいいじゃん。

一致した行自体も出るけど、エスパーするとむしろその方がいいと出てる。
0018名無しさん@お腹いっぱい。2012/06/09(土) 13:57:44.31
>>17
それは一致した行の次の行を取り出したい場合だろw 欲嫁
0019名無しさん@お腹いっぱい。2012/06/09(土) 14:01:37.89
なぜにfgetsじゃなくてfgetc?
0020名無しさん@お腹いっぱい。2012/06/09(土) 14:07:19.90
…などとデバッグしてるぐらいなら head -n 2 | tail -n 1 の方がずっと早いな。
まあ、ふつーはそれすらせずに>>15だが。
0021名無しさん@お腹いっぱい。2012/06/09(土) 14:18:33.49
「grepで引っかかる行が10行あります。これら10行それぞれの次の行(2行目)を
取り出したいのですが、何か簡便な方法はありませんか?」

という質問だったとしたら?
0022名無しさん@お腹いっぱい。2012/06/09(土) 14:18:49.34
効率的には grep -m2 〜 | tail -n1 とかの方がいいのかね
0023名無しさん@お腹いっぱい。2012/06/09(土) 17:31:36.34
>>16
あんまり釣れないね。
0024名無しさん@お腹いっぱい。2012/06/09(土) 21:38:41.95
質問がわかりにくくて済みません。実は >>21 さんの意味で質問しました。
何か簡便な方法がありましたらお願いします。
0025名無しさん@お腹いっぱい。2012/06/09(土) 21:46:40.88
>>24
次の行も欲しいってのなら>>17の言うとおり-Aオプション使うのが簡単じゃないかな
次の行だけ欲しいってのならgrep 〜 | sed -n '/pattern/{n;p}' とか。まあこれは2行連続でパターンマッチする可能性がある場合は使えないんだけど。
あとはawkかperlあたりで適当なスクリプト組むくらいかねえ
0026252012/06/09(土) 21:49:49.12
しまった >>25 は grep 必要なかった
0027名無しさん@お腹いっぱい。2012/06/10(日) 05:16:55.25
環境変数IFSってforとread以外に使い道あるのかしら
0028名無しさん@お腹いっぱい。2012/06/10(日) 14:21:25.03
コマンドを実行した複数行の結果を変数に格納した後、その各行に処理を行いたいのですが、
たとえば
hoge=`ls -l`
とやると、改行が格納されません。
改行を含めた結果を格納するのはどのようにしたら良いのでしょうか?
0029名無しさん@お腹いっぱい。2012/06/10(日) 14:32:53.34
>>28
hoge=`ls -l` で改行は格納される。

echo $hoge ではなく、

echo "$hoge"
で変数の値を取り出すこと。
0030名無しさん@お腹いっぱい。2012/06/10(日) 14:43:07.38
早速の回答、誠にありがとうございまする
0031名無しさん@お腹いっぱい。2012/06/12(火) 18:12:34.43
ls -1 | nohup xargs -L1 -P20 -I@ sh -c "./a.out @ < @.txt > @.log 2> err.log" > progress.log &
このコマンドどこに問題がありますか?
最初の20行分しか処理されずに止まっちゃうんだけど・・・泣
0032名無しさん@お腹いっぱい。2012/06/12(火) 18:19:37.78
expectコマンドを使わずにシェルスクリプトでパスワードを自動入力させるにはどのようにすればよいでしょうか?

#!/bin/bash
ssh user@hostname
パスワードを入力するコマンド

上記のようなスクリプトが作りたいです。
どなたか教えて頂けないでしょうか。よろしくお願いします。
0033名無しさん@お腹いっぱい。2012/06/12(火) 18:34:26.09
>>32
echo unko | ssh user@hostname
0034名無しさん@お腹いっぱい。2012/06/12(火) 18:46:46.29
>>32
公開鍵認証じゃだめなん?
0035名無しさん@お腹いっぱい。2012/06/12(火) 18:49:57.90
>>33
それじゃだめじゃね。
0036名無しさん@お腹いっぱい。2012/06/12(火) 18:59:21.99
質問者ですが、
>>31
はスレチでした?
0037名無しさん@お腹いっぱい。2012/06/12(火) 19:06:40.96
>>33
試してみたのですが、パスワード入力を求められました。。

>>34
パスワード入力したいです。
0038名無しさん@お腹いっぱい。2012/06/12(火) 19:16:56.47
>>31
20行毎に別々に sh -c "...." が起動されるから、
> @.log 2> err.log とかが全部上書きされて
最後に書いた20行分しか残らない。
0039名無しさん@お腹いっぱい。2012/06/12(火) 20:08:55.76
>>38
すみませんが詳しい方のみ回答をお願いします
0040名無しさん@お腹いっぱい。2012/06/12(火) 20:17:55.37
>>31
> progress.log じゃなくて
>> progress.log じゃないの?
0041名無しさん@お腹いっぱい。2012/06/12(火) 20:20:23.43
>>40
すみませんが詳しい方のみ回答をお願いします
0042名無しさん@お腹いっぱい。2012/06/12(火) 20:26:15.13
パイプ出力なのに ls -1 とかやるのは素人
0043名無しさん@お腹いっぱい。2012/06/12(火) 20:29:12.04
すみませんが詳しい方のみ質問をお願いしますw
0044名無しさん@お腹いっぱい。2012/06/12(火) 20:29:30.99
>>42
すみませんが詳しい方のみ回答をお願いします
0045名無しさん@お腹いっぱい。2012/06/12(火) 20:31:12.33
すみませんが詳しい方のご健闘をお祈りします
0046名無しさん@お腹いっぱい。2012/06/12(火) 20:33:43.17
>>42
findってこと?
結局どうすれば正解なの?
入力(ls -1):
a
b
c
d
e
f
実行されたいコマンド(xargs -L1 -P2)
./a.out a
./a.out b
====終わってから
./a.out c
./a.out d
====終わってから
./a.out e
./a.out f
って感じにしたいわけだけど。
0047名無しさん@お腹いっぱい。2012/06/12(火) 20:35:02.58
ちなみに39とかは質問者(31+46)じゃないから。
お願いだから邪魔しないで。
0048名無しさん@お腹いっぱい。2012/06/12(火) 20:44:15.91
出力はまああまり気にしてなくて、
むしろ
./a.out a
./a.out b
====ここで止まっちゃう
のが大問題。
0049名無しさん@お腹いっぱい。2012/06/12(火) 21:29:01.48
>>46
>>42
が言ってるのは出力が端末でないなら ls -1 しなくても ls でいいって話.

xargs -L1 -P2の挙動があくまで2プロセス同時にやるって話だから
./a.out aが先に終われば ./a.out bが終わる前に ./a.out cを先に実行する
望みの挙動にするのは一行スクリプトだと割と面倒だから素直にmakeで依存関係書いてmake -j 20とかした方がいいかも

ちなみに俺の環境で >>31 を試してみたけどちゃんと20行以降も実行される.
可能性として気になったのはnohupの位置なんだけど
もしかして実行開始してから端末閉じたりしてる?
0050名無しさん@お腹いっぱい。2012/06/12(火) 22:31:56.89
>>49
丁寧にありがとう。
しばらく使わないと忘れるんだけど、
> ./a.out aが先に終われば ./a.out bが終わる前に ./a.out cを先に実行する
これはまったく問題ない。説明不足ですまんかった。

> もしかして実行開始してから端末閉じたりしてる?
たぶん、それが原因だと思う。
ただ、xargの中に入れるのも混乱してしまうんだ。
どうすればうまく生き残るの?
0051名無しさん@お腹いっぱい。2012/06/12(火) 22:39:01.73
>>50
俺はnohupの挙動がちょっと曖昧だから確信持てないけど
nohupを先頭に持ってくるか
#!/bin/sh
ls -1 | xargs ...
っていうのを書いたファイル用意してnohup付けて実行するとか
あとはnohupじゃなくてCtrl-Zで一時停止 -> bg -> disown したり screen で代用してみるとか

0052名無しさん@お腹いっぱい。2012/06/12(火) 23:12:10.37
>>51
めっちゃ参考になる。ありがとう。
なんかパイプで色々つなぐのはいいけど、結局クォーテーションマークで躓くんだよね。
もうちょっと真面目に考えて設計してほしいわ。
0053名無しさん@お腹いっぱい。2012/06/13(水) 00:35:25.15
少なくともバッチ処理なんだから nohup とか使うんじゃなくて batch とか
at コマンド使うほうが素直な気がする。

もっともバッチ処理システム入れて管理すれば batch コマンド以上に
いろいろかゆいところに手が届いていいと思うが。
0054名無しさん@お腹いっぱい。2012/06/14(木) 14:17:28.57
echo *.csv | cat

だとファイル名が表示されるだけで、

echo *.csv | xargs cat

だとファイルの中身が表示されるのはなぜでしょうか?
xargsを付けなくてもファイルの中身が表示されると思ってました。。
0055名無しさん@お腹いっぱい。2012/06/14(木) 14:20:16.35
cat がそういう作りだから。
man cat 読め。
0056名無しさん@お腹いっぱい。2012/06/14(木) 14:23:59.09
>>54の挙動だと、

$ echo 54nobaka | cat
54nobaka
は間違いで、
$ echo 54nobaka | cat
cat: 54nobaka: No such file or directory
が正しいと言うことになるな。
あり得ん。
0057名無しさん@お腹いっぱい。2012/06/14(木) 14:28:27.78
cat *.csv

だとファイルの中身が表示されるのに、

echo *.csv | xargs cat

だとそのようなファイルやディレクトリはありませんになることがあります。

man cat 読んでもわかりません。
0058名無しさん@お腹いっぱい。2012/06/14(木) 14:30:22.51
>>56
cat: 54nobaka: No such file or directory
の意味は分からなかったけど、標準入力に渡してもダメ、引数に渡せってこと?
0059名無しさん@お腹いっぱい。2012/06/14(木) 14:41:19.14
>>57
*.csv にマッチするファイルがないから
*.csv がそのまま渡った、とかじゃないの。

>>58
そう。
引数なしの cat は
標準入力から受け取ったものをそのまま標準出力に渡す。
0060名無しさん@お腹いっぱい。2012/06/14(木) 14:44:47.08
>>59
なるほど。ありがとうございます!

cat *.csvとすれば良いから、わざわざ|とexec使う必要もなかったですね。
0061名無しさん@お腹いっぱい。2012/06/14(木) 14:49:06.50
>>59
>*.csv にマッチするファイルがないから

*.csv にマッチするファイルはあります。
0062名無しさん@お腹いっぱい。2012/06/14(木) 14:51:34.83
>>61
んじゃファイル名にスペースが入ってるとか。
0063名無しさん@お腹いっぱい。2012/06/14(木) 15:02:46.51
ファイル名にスペースは入ってません。
0064名無しさん@お腹いっぱい。2012/06/14(木) 15:12:33.68
>>63
んじゃ具体的にどういうファイルがあるの?
0065名無しさん@お腹いっぱい。2012/06/14(木) 15:21:51.24
年金記録-'06〜'10.csv
0066名無しさん@お腹いっぱい。2012/06/14(木) 15:27:40.76
' ' が解釈されちゃってるな。
0067名無しさん@お腹いっぱい。2012/06/14(木) 15:43:59.51
>>65
これは非道い。
オレには、ファイル名にクオテーションやダブルクオテーションを含める勇気はないわ
0068名無しさん@お腹いっぱい。2012/06/14(木) 18:24:41.60
>>65
んじゃこれは
*\'*\'*.csv
でいけるのかな?
0069名無しさん@お腹いっぱい。2012/06/14(木) 18:28:50.78
>>68
そんなことしても xargsの段階で解釈されるから無理だろ
0070名無しさん@お腹いっぱい。2012/06/14(木) 18:45:30.67
どうしてもecho使いたいって条件だとキツいね
Linuxのlsなら-Qオプション使えるから
ls -Q *.csv | xargs cat
するかfind の -print0 と xargs の -0 組み合わせるぐらいだろうか。
まあfind使うならxargsじゃなくて-exec使えって話なんだろうが。
0071名無しさん@お腹いっぱい。2012/06/14(木) 18:51:16.77
あとは普通にfor文使うとか
ファイル名に空白がある場合は使えないけど
$ echo -n *.csv | xargs -d ' ' cat
という説もある
0072名無しさん@お腹いっぱい。2012/06/15(金) 07:48:47.63
すんません、ディレクトリツリー内で作成日時が最古のファイルを取得できるコマンドを教えてくださいませんか
0073名無しさん@お腹いっぱい。2012/06/15(金) 08:16:08.73
>>72
一般的な方法はない。
0074名無しさん@お腹いっぱい。2012/06/15(金) 08:23:01.23
>>73
すみませんが詳しい方のみ回答をお願いします
0075名無しさん@お腹いっぱい。2012/06/15(金) 08:28:15.12
>>72
lsで日付順で取得してheadまたはtailじゃオーバーヘッド大きすぎ?
うちはめんどくさいからそれで済ませてるんだが
0076名無しさん@お腹いっぱい。2012/06/15(金) 08:33:32.64
>>75
ディレクトリ「ツリー」だから、そもそもlsで日付順で取得できないだろw
0077名無しさん@お腹いっぱい。2012/06/15(金) 08:44:08.87
>>75
それ作成日時じゃないよ。
0078名無しさん@お腹いっぱい。2012/06/15(金) 08:48:48.06
あんまり巨大なツリーじゃなければ、zsh あたりで
ls -dtr **/* | head -1
とかか。

お題としては、ls -D か stat あたり使って、
巨大なツリーで日付ソートしろっていう方が楽しいけど。

ただし、「作成日時」には目をつぶる。
0079名無しさん@お腹いっぱい。2012/06/15(金) 08:52:37.74
そこ目をつぶっちゃだめだろw
0080名無しさん@お腹いっぱい。2012/06/15(金) 08:55:56.64
lsって最終変更日時とか状態変更日時とかアクセス日時は取れるのに、作成日時だけ取れないのな。
知らんかった。すまん。
0081名無しさん@お腹いっぱい。2012/06/15(金) 09:03:13.70
取れるかどうかの問題じゃなくて、その情報があるかどうかだ
0082名無しさん@お腹いっぱい。2012/06/15(金) 09:10:31.17
>>72
find /dir -printf '%T+ %p\n' | sort | head -1
0083名無しさん@お腹いっぱい。2012/06/15(金) 09:35:24.92
>>82
それ作成日時じゃないよ。
0084名無しさん@お腹いっぱい。2012/06/15(金) 09:40:26.32
>>83
そういうのはいいです。エスパーなら最終更新日時と詠み換えるべき。
0085名無しさん@お腹いっぱい。2012/06/15(金) 09:42:24.84
エスパーじゃないもの。
書いてあることしか読み取れんよ。
0086名無しさん@お腹いっぱい。2012/06/15(金) 10:07:26.75
>>72は聞いたっきり現れないな。
こりゃ釣られたか。
0087名無しさん@お腹いっぱい。2012/06/15(金) 10:13:35.22
ツリーだけに…
0088名無しさん@お腹いっぱい。2012/06/15(金) 10:44:32.41
ぷぷ
0089名無しさん@お腹いっぱい。2012/06/15(金) 20:59:46.79
作成時刻を保持してるUNIX系OSってあるの?
0090名無しさん@お腹いっぱい。2012/06/15(金) 21:05:44.38
UFS2にbirthtimeってのがあるらしい。
0091名無しさん@お腹いっぱい。2012/06/15(金) 21:10:03.64
Linuxのext4にもbirth timeあるね
0092名無しさん@お腹いっぱい。2012/06/16(土) 09:05:43.92
>>82
GNU依存乙
0093名無しさん@お腹いっぱい。2012/06/17(日) 08:29:54.78
GNU dateが無いともう生きていけません
完全に陥落しました
0094名無しさん@お腹いっぱい。2012/06/17(日) 14:58:07.56
>>93
どんな時に便利っすか
0095名無しさん@お腹いっぱい。2012/06/17(日) 15:13:21.09
前日の日付を取得するときとか。
0096名無しさん@お腹いっぱい。2012/06/17(日) 17:40:13.73
それは定番の手法があるだろう。
0097名無しさん@お腹いっぱい。2012/06/17(日) 17:51:43.63
GNU date使うと楽すぎて。
0098名無しさん@お腹いっぱい。2012/06/17(日) 17:52:22.83
あと変数でn日前とかも楽。
0099名無しさん@お腹いっぱい。2012/06/18(月) 09:39:45.83
こんな感じっすか。

env TZ=JST+15 date
n=5
date -v -${n}d
0100名無しさん@お腹いっぱい。2012/06/18(月) 12:19:00.38
n=20
0101 忍法帖【Lv=40,xxxPT】 2012/06/18(月) 14:36:30.11
タイムゾーンを取得する方法を教えな
0102名無しさん@お腹いっぱい。2012/06/19(火) 00:23:33.59
ターイムゾーンと叫べ!
0103名無しさん@お腹いっぱい。2012/06/19(火) 01:23:21.92
>>99
世界にはタイムゾーンがいくつもある、という事をよく分かっていない人が
そういう手法を取る結果、スクリプトがおかしな動作をする

…というところから、GNU版dateの拡張は始まっている

NetNewsがまだ生きてた時代の話
0104名無しさん@お腹いっぱい。2012/06/19(火) 09:28:29.09
世界にはタイムゾーンはいくもあるけど、
サーバは1ヶ所にあって世界中を旅するわけではないので。
0105名無しさん@お腹いっぱい。2012/06/19(火) 11:04:50.48
クライアントじゃなくてサーバかよw
0106名無しさん@お腹いっぱい。2012/06/19(火) 11:28:22.18
>>105
何かおかしいか?
0107名無しさん@お腹いっぱい。2012/06/19(火) 11:43:09.74
>>105
笑い事じゃあないぞ
0108名無しさん@お腹いっぱい。2012/06/19(火) 11:51:13.75
WebAppフレームワーク系は複数のタイムゾーン扱う仕組み持ってるよ。
django1.4もmultiple time zoneが入ったばかり。
default time zoneもcurrent time zoneも取得できる。
夏時間と遠隔地絡んだ特殊な処理も標準的にできるようになった。
またWebAppサーバのdefault time zoneはサーバの物理的な位置に合わせていると限らない。

まあシェルスクリプトの領分ではないが。
■ このスレッドは過去ログ倉庫に格納されています