トップページ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/
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はサーバの物理的な位置に合わせていると限らない。

まあシェルスクリプトの領分ではないが。
0109名無しさん@お腹いっぱい。2012/06/19(火) 12:02:54.39
date +%Z でいいんじゃね?

sshした時にTZはクライアントのがいいか、サーバのがいいかなんて一意には決められないね。
環境変数TZは、最小限の手間でその辺のことうまく扱ってるね。
0110名無しさん@お腹いっぱい。2012/06/19(火) 19:27:08.84
世界のどこか、例えばエスポレル共和国から日本のサーバにsshでアクセスし、
エスポレル共和国時間で12時間前の時刻を計算したいときって、どうすればいいの?
0111名無しさん@お腹いっぱい。2012/06/19(火) 19:33:35.80
>>110
エスポレル共和国ってどこだか知らないけど、
タイムゾーンはどうなってるの?
0112名無しさん@お腹いっぱい。2012/06/19(火) 19:34:09.40
それってsshで日本のサーバーにアクセスしてることと何か関係あるの?
いったんログアウトしてエスポレル共和国のマシンで好きにやったらいいじゃんw
0113名無しさん@お腹いっぱい。2012/06/19(火) 20:07:19.80
>>110
$ env TZ='エスポレル共和国のタイムゾーン' date --date='12 hours age'
でいいんじゃない?

GNU date依存嫌ならepoch time計算して。
0114ワラ2012/06/19(火) 20:11:25.70
age→ago
0115名無しさん@お腹いっぱい。2012/06/19(火) 21:34:29.04
>>113
でもそのスクリプトだと、別のタイムゾーンのどこかの国からアクセスした場合でも
アクセス元ではなく、常にエスポレル共和国の計算結果が出てしまうのでは
0116名無しさん@お腹いっぱい。2012/06/19(火) 22:00:52.43
つまり「ログイン元のサーバのタイムゾーンをログイン先にも反映させたい」ってこと?
それはsshのサーバ/クライアントの設定で環境変数TZを引き渡せるように
AcceptEnv/SendEnvやPermitUserEnviromentするぐらいしかないんじゃなかろうか。
0117名無しさん@お腹いっぱい。2012/06/19(火) 22:13:50.40
>>115
でも最初にそういう条件なかったよね。
0118名無しさん@お腹いっぱい。2012/06/20(水) 11:35:27.52
>>115
その先の創意工夫は自分でやるんだよ
なんでもおんぶにだっこじゃ教育によくない
0119名無しさん@お腹いっぱい。2012/06/20(水) 14:14:27.58
>>117
最初の一行目に世界のどこか、例えばって書いてあるのになにいってんの?
0120名無しさん@お腹いっぱい。2012/06/20(水) 14:28:46.20
なんか、途中から入ってきた人が意味取り間違えて会話してるね。

お題を整理しよう。

環境変数TZがすでに設定されている(日本時間とは限らない)場合も含めて、
GNU dateを使わずに、dateで1日前の日付(時刻)を取得する方法は?

というのが元のお題。
0121名無しさん@お腹いっぱい。2012/06/20(水) 14:37:08.98
>>119
ん?
どういうこと?
0122名無しさん@お腹いっぱい。2012/06/20(水) 14:40:02.24
>>120
GNU date ない環境では perl でワンライナー書いてたな。
perl すらない環境には当たったことがなかった。
0123名無しさん@お腹いっぱい。2012/06/20(水) 14:40:54.15
BSD dateはいいのか?
0124名無しさん@お腹いっぱい。2012/06/20(水) 14:43:50.35
>>123
なるべく汎用性が高い方法で、ってことじゃないなあ。
0125名無しさん@お腹いっぱい。2012/06/20(水) 14:45:03.99
×じゃないなあ
○じゃないかな
0126名無しさん@お腹いっぱい。2012/06/20(水) 14:56:47.76
>>123
>>99で出てるな。
0127名無しさん@お腹いっぱい。2012/06/20(水) 15:04:20.81
JSTとかPDTとかってどうやって取得すんの?
0128名無しさん@お腹いっぱい。2012/06/20(水) 15:06:30.87
>>122
perlといってもうちの環境じゃコアモジュールすら無いけどな
何をやるにも車輪作り直しだから楽しいといえば楽しい
0129名無しさん@お腹いっぱい。2012/06/20(水) 15:11:35.40
>>128
そういう環境では>>120はどうやるの?
0130名無しさん@お腹いっぱい。2012/06/20(水) 15:22:57.02
>>129
諦めてた
0131名無しさん@お腹いっぱい。2012/06/20(水) 15:24:14.50
コアモジュールなくても、timeとlocaltimeとprintくらいないの?
0132名無しさん@お腹いっぱい。2012/06/20(水) 16:40:08.45
>>131
標準関数はだいたいある
昨日の日付くらいなら自力でなんとかなるよ
0133名無しさん@お腹いっぱい。2012/06/24(日) 21:01:25.05
expectを使用してlsコマンドを発行、
その結果をスクリプト内の変数に入れるにはどうすればいいのん?
コマンド発行まではググってすぐにわかったんだけど結果取得がよくわかんない(´・ω・`)
0134名無しさん@お腹いっぱい。2012/06/24(日) 21:07:37.57
普通に ` ` じゃだめなん?
0135名無しさん@お腹いっぱい。2012/06/24(日) 21:54:23.75
expect内でtelnet接続
その接続先でコマンドを発行して結果を取得したいのです…
0136名無しさん@お腹いっぱい。2012/06/24(日) 22:09:29.98
それは大変高度な要求なので答える事が出来るのは日本に1人しかいない。
0137名無しさん@お腹いっぱい。2012/06/24(日) 22:10:23.28
>>135
そういうことなら ssh 使う方が楽じゃない?
0138名無しさん@お腹いっぱい。2012/06/24(日) 22:12:20.95
expect+telnetなんて使わずに普通にssh使え。
0139名無しさん@お腹いっぱい。2012/06/24(日) 23:24:18.51
>>135
前回の expect から今回の expect までの文字列すべてが $expect_out(buffer) に
格納されるから、それを処理すればよい。
以下は /var/log/wtmp のファイルサイズを取得する例。

send -- "ls -al /var/log | egrep -e \"\[ \]wtmp$\"\r"
set bprompt 0
while { $bprompt < 1 } {
expect {
# わざと "\r\n" で expect 掛けて、1行1行ぶつ切りにしてプロンプト手前の1行だけ回収。
-re "\r\n" { set last_line $expect_out(buffer) }
-re ".*\[\$\] " { set bprompt 1 }
}
}

# 正規表現で ls の5カラム目だけ $fsize に切り出し。
if { [ regexp {^\S+\s+\S+\s+\S+\s+\S+\s+(\S+)\s} $last_line i_all fsize ] } {
send -- "export WTMPSIZE=$fsize\r"
}
0140名無しさん@お腹いっぱい。2012/06/24(日) 23:44:45.76
自分で書いててなんですが、ls /var/log/wtmp でいいですよね。
出力行数をコマンド側で極力減らしておく、ということを言いたかったのですが
例としては不適切でした。
0141ワラ2012/06/25(月) 23:34:27.36
>>133>>135
シェルスクリプトはどちらで動くのですか?
0142名無しさん@お腹いっぱい。2012/06/26(火) 09:23:23.94
回答が全て難しすぎてワロタ
expect -c "
spawn telnet 127.0.0.1
expect \"$ \"
send \"ls\r\"
expect eof
"
こんな風に書いてて
「よーしとりあえずexpectの外でecho $expect_out(buffer)を入れてlsの結果を表示するぞー」
とか思ってたらなんかどこに入れるかわからんかった
というより、expectの使い方がわかってない気がした…
0143名無しさん@お腹いっぱい。2012/06/26(火) 11:39:01.09
回答が難しいってより質問がわけわからんくて。
鍵設定して
OUT=`ssh hoge@127.0.0.1 ls`
とかでいいじゃん。
0144名無しさん@お腹いっぱい。2012/06/26(火) 12:03:19.34
ふむ。
端からexpectありき、で考えること自体が間違っているわな。
0145名無しさん@お腹いっぱい。2012/06/26(火) 15:29:34.23
telnet接続限定なのでどうしてもexpectを使用してlogin passwordを自動化しないといけないんですよね…
0146ワラ2012/06/26(火) 15:57:31.38
>>141はどうなんだよ。

シェルスクリプトは全部こっちで動かすとして、

#! /usr/bin/expect -f
spawn telnet ホスト名
expect "login:\ "
send "ログイン名\r"
expect "assword:"
send "パスワード\r"
expect "^ホゲ$ "
send "ls¥r"
expect "^ホゲ$ "
send "exit\r"

を下請けコマンドにしてやってみれ。(プロンプトは"ホゲ$ "と仮定)
0147名無しさん@お腹いっぱい。2012/06/26(火) 16:08:59.94
質問者は名前書いとくれ。
01481332012/06/26(火) 16:18:50.38
>>146
動かす方は全てクライアント側です
早速そのスクリプトをe.shで保存
expect e.shとして接続を確認
呼び出し側のスクリプトclient.shで
#!/usr/bin/env bash
OUT=`expect e.sh`
echo $OUT
とするとConnection closed by foreign host.oel Chiappa.c. Reserved.というエラーが…
むむむ…
0149名無しさん@お腹いっぱい。2012/06/26(火) 16:21:53.21
ルータか?
ならそれを先に言えよ。
そもそもls使えんのか?
01501332012/06/26(火) 16:25:27.80
Yes
シリアル接続のルータです
lsは仮で使用出来るコマンドを発行してます
でもexpect -f e.sh や expect e.shだとOKなんですが
シェルスクリプト内でやると駄目だよーと怒られるんです(´・ω・`)
0151名無しさん@お腹いっぱい。2012/06/26(火) 16:27:25.92
「駄目だよー」じゃわからん。
0152名無しさん@お腹いっぱい。2012/06/26(火) 16:27:40.89
×シリアル接続のルータ
○シリアル接続が出来るルータ
0153名無しさん@お腹いっぱい。2012/06/26(火) 16:28:08.54
ウソついたり隠し事したりするやつはめんどう見きれん。
01541332012/06/26(火) 16:28:19.13
>>151
エラー内容は>>148です
0155名無しさん@お腹いっぱい。2012/06/26(火) 16:29:27.55
たぶんそれ出来ないよ。
だからperl何かをみんな使う。
0156名無しさん@お腹いっぱい。2012/06/26(火) 16:29:29.22
>>154
それエラーじゃないでしょ。
向こう側が接続を切った、って言ってるだけ。
01571332012/06/26(火) 16:33:03.55
>>155
そうなんだ…
>>156
expect e.shだと出来るんですよね
でもシェルスクリプト内で呼び出すと先ほどのエラーがでちゃう
うーむ…
0158名無しさん@お腹いっぱい。2012/06/26(火) 16:40:34.41
>>157
標準出力が端末以外の状態だとダメなんだろ。

expect e.sh だとOKでも、
expect e.sh | cat ではNGとか。

だったら OUT=`expect e.sh` も NGになる。
01591332012/06/26(火) 16:44:09.27
>>158
いえ、expect e.sh | catと打ち込んでも出来ました
でもシェルスクリプト内で>>148のようにするとエラーが返って来ちゃうんです
0160名無しさん@お腹いっぱい。2012/06/26(火) 16:48:13.20
>>159
シェルスクリプトの「外」で、

OUT=`expect e.sh`
echo "$OUT"

って打ち込むとどうなる?
0161ワラ2012/06/26(火) 16:49:51.33
J. Noel Chiappaさん、久しぶりだなあ。
01621332012/06/26(火) 16:50:03.46
>>160
>>148のエラーが$OUTにはいってました
0163名無しさん@お腹いっぱい。2012/06/26(火) 16:53:23.12
>>162
じゃあ、

expect e.sh > OUT
cat OUT

で妥協。
01641332012/06/26(火) 16:57:30.29
>>163
ばっちり出来ますた!
ちなみに別ファイルを用意せずにシェルスクリプト内でexpect -c ""みたいにする事は出来ないのかな?
出来ないから別ファイル用意してexpectやperlを使用するようにと言われてるような気もするけど…
0165ワラ2012/06/26(火) 17:02:26.40
出来るよ。
たぶんあんたが色々勘違いしてるだけ。
ルータの連続ログイン禁止に抵触してたり。
エラー処理がない>>146もどうかと思うけど。
0166名無しさん@お腹いっぱい。2012/06/26(火) 17:04:50.56
>>165
連続ログイン?
そういったルールによるアクセス制御はありませんよ
ちなみにexpect -cだと具体的に>>146はどう書くんです?
■ このスレッドは過去ログ倉庫に格納されています