LINUXコマンドでこんなことできますか?という質問です。解決案に500Pお支払いします。


何らかの処理が「5秒以内」に終了しなかったら、強制終了(kill)みたいなことをしたいです。

例)nkf hoge.txt して5秒以内に完了しないなら、強制終了。

シェルスクリプトを作るのではなく、コマンドで出来たら有り難いです。ワンライナーで。

超適当)nkf hoge.txt >dev/null &|sleep 5|ps nkf|kill nkf みたいな。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2010/02/17 15:45:03
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

回答16件)

id:longicorn No.1

回答回数56ベストアンサー獲得回数6

ポイント17pt

難しい事を考えずに、普通に5秒後にkillすれば良いだけでは?

5秒後に終了していたらkillしても問題ないですし(killできないだけ)、nkfが5秒後に起動していればそのままkillします。


sh "nkf hoge.txt >dev/null &";sleep 5;kill -kill nkf

自分の環境でテストしたところ、"&;"がまずいのでshから起動しています。


ただし、他のnkfが起動していないことが前提です。

id:logihot

ありがとうございます。質問に漏れている項目で、実行するコマンドの出力結果は欲しいです。バックグランド実行だと、結果が分からないので、その辺を解決するのは難しいでしょうか。

nkfの例が悪かったのですが、例えば、convert とか find とかの結果を知る処理が5秒後にも走っていたら、結果をかえさずにkillしたいです。

正常なら)結果を返す

不良なら)killしてエラー返す

2010/02/10 17:49:07
id:dev_zer0 No.2

回答回数332ベストアンサー獲得回数25

ポイント17pt

前提条件

・他にnkfが動いていないこと

・pkillがあること

pkillが無い場合、おとなり質問の

http://q.hatena.ne.jp/1254302163

を参照してください。

nkf hoge.txt > dev/null & ( sleep 5 ; pkill nkf )

バックグラウンドでnkfを走らせ、サブシェルで5秒後にnkfプロセスのkillを試みます

id:logihot

ありがとうございます。質問に漏れている項目で、実行するコマンドの出力結果は欲しいです。バックグランド実行だと、結果が分からないので、その辺を解決するのは難しいでしょうか。

nkfの例が悪かったのですが、例えば、convert とか find とかの結果を知る処理が5秒後にも走っていたら、結果をかえさずにkillしたいです。

正常なら)結果を返す

不良なら)killしてエラー返す

2010/02/10 17:49:11
id:daginn No.3

回答回数7ベストアンサー獲得回数0

ポイント17pt

command >/dev/null & sleep 5; kill $!

commandをバックグラウンドで実行すると、

$!には直前のバックグラウンドジョブ(=command)のPIDが入っているので、それで殺せます。

実行例

$ yes >/dev/null & sleep 5; kill $!

[1] 11112

(5秒経過)

[1]+ Terminated yes > /dev/null

$

id:logihot

ありがとうございます。質問に漏れている項目で、実行するコマンドの出力結果は欲しいです。バックグランド実行だと、結果が分からないので、その辺を解決するのは難しいでしょうか。

nkfの例が悪かったのですが、例えば、convert とか find とかの結果を知る処理が5秒後にも走っていたら、結果をかえさずにkillしたいです。

正常なら)結果を返す

不良なら)killしてエラー返す

2010/02/10 17:49:12
id:tomkano1 No.4

回答回数43ベストアンサー獲得回数0

ポイント17pt

すいません

わかりません

id:logihot

了解です^^

2010/02/10 17:45:19
id:qnighy No.5

回答回数19ベストアンサー獲得回数1

ポイント16pt

daginnさんの

command >/dev/null & sleep 5; kill $!

で、">/dev/null"の部分を無くして

command & sleep 5; kill $!

とすればcommandの出力も見られると思います。

これにif文をつけて

command & sleep 5; if kill $!; then echo "failed."; fi

とすれば、killに成功(5秒以内の実行に失敗)した場合の処理を記述できます。

id:logihot

実現が近くなり、感謝します。また、説明不足が多く申し訳御座いません。

正常な場合は、即時結果が知りたく、異常な場合は、5秒後にエラーを通知したいです。

つまり、正常な場合は、5秒待たずに結果だけを先に出力して、処理を終わらせるか、kill部分をバックグランドに渡したいです。

PHPからコマンドを呼び出すのですが、正常な場合は即時結果が欲しく、異常な場合でも5秒以内には結果が欲しいため、このような質問をさせて頂きました。

頂いた方法ですと、どうしても結果を得るまでに5秒かかってしまい、異常な場合は対応できるのですが、正常パターンで即時結果だけ欲しい部分が何とかならないかと悩んでおります。

2010/02/10 18:21:56
id:cannabis_c4 No.6

回答回数20ベストアンサー獲得回数4

ポイント16pt

質問内容がコロコロ変わっているようなので、期待に添えるかいまいちわかりませんが、こういうことでしょうか?

<?php
ob_start();
system('nkf hoge.txt & sleep 5; kill $! && false', $retval);
if ($retval) { ob_end_clean(); echo "タイムアウトのため中途終了しました\n";}
ob_flush();
?>

ちなみに、どんな高性能なコンピュータでも1秒たりとも未来の処理結果を予測することはできません。

>>つまり、正常な場合は、5秒待たずに結果だけを先に出力して、

という処理は未来予測にあたるため不可能です。

shellスクリプトであれば出力をtmpファイルに、phpであれば上記にように終了結果が出るまでバッファリングする必要があります。

id:logihot

申し訳ないです。試して見ます!ありがとうございます。

2010/02/10 20:01:03
id:qnighy No.7

回答回数19ベストアンサー獲得回数1

ポイント16pt

ちょっと長いけどできました。Linuxなら実行できると思います。

(sleep 5;echo "aborted.";kill -- -`ps -o pgid --no-headers -p $$`)& command;echo "finished.";kill $!

また、以下のようなページを発見しました。参考程度に。

http://d.hatena.ne.jp/hcr/20050803/1123025377

それと、手元のUbuntuでは"timeout"というそのものずばりなパッケージがありました。

timeout 5 sleep 10

など超簡単に使えるので、お使いのLinuxにこのパッケージが存在して、かつ管理者権限がある(または管理者にインストールを頼める)場合はこれが一番いいと思います。

id:logihot

試してみました!ただ、2点、実現できない部分があります。

1つは、異常処理の場合、5秒経ってもkillできませんでした。

2つは、LINUXからは正常処理の場合、すぐに結果が返ってきましたが、PHPから行うと、正常でも異常でも必ず5秒は待つ必要がありました。

exec((sleep 5;echo "aborted.";kill -- -`ps -o pgid --no-headers -p $$`)& command;echo "finished.";kill $!);

?>

2010/02/10 21:23:39
id:kaosu-0817 No.8

回答回数6ベストアンサー獲得回数0

あまり分からないけど、

やればできると思います!

がんばってください!

...質問に答えてませんね...

すいませんでした!

id:logihot

ありがとうございます。。

2010/02/10 21:21:07
id:yu-inazuma No.9

回答回数3ベストアンサー獲得回数0

すいません。ぜんぜんわかりません。

id:logihot

どうもです

2010/02/10 21:21:21
id:t-wata No.10

回答回数82ベストアンサー獲得回数13

ポイント16pt
#!/bin/sh
set -m
nkf hoge.txt&
(sleep 5&&kill $!) >/dev/null 2>&1&
fg %1
if [ "$?" != 0 ]; then
  echo ERROR
fi

のように目的のプロセスとkillするプロセスとをともにバックグラウンドで動かした後、

目的のプロセスをフォアグラウンドに持ってこれば、

正常な場合は、即時結果が知りたく、異常な場合は、5秒後にエラーを通知したいです

は実現できます。残念ながらワンラインではできませんが。

id:logihot

ありがとうございます!試して見ます!

ただ、上記コードだと、即時結果は分かるけど、fiまでいくのに5秒必要な感じでしょうか

2010/02/10 22:41:09
id:b-wind No.11

回答回数3344ベストアンサー獲得回数440

ポイント16pt

やたらややこしい割に条件後出しか。めんどくさいね。

bash -c 'nkf hoge.txt 2>&1 & ; PROCESS=$!; ( wait && kill -KILL $$ ) & ; ( sleep 5; kill -KILL $PROCESS > /dev/null 2>&1 && echo "time out" 1>&2 ) &'

Manpage of BASH

ちょと終了処理はサボってるけどこんな所か?テストはしてない。


シェルスクリプトを作るのではなく、コマンドで出来たら有り難いです。ワンライナーで。

何か勘違いしているようだがワンライナーは立派なシェルスクリプトだよ。

ファイルに書いてないだけで。

id:logihot

ごめんなさいねー!回答ありがとうございます!

試してから、連絡します。

2010/02/11 15:16:51
id:mjy No.12

回答回数70ベストアンサー獲得回数22

ポイント16pt

hoge_command の出力を、less で受け取るとします。

(5秒たったら停止)

長いですが、ワンライナーでやると以下のようになります。

hoge_command |bash -c 'bash -c "sleep 5; test -e /proc/$$ && kill -KILL $$" >/dev/null & disown $!; exec cat -n /dev/stdin' |less

「'」 と「 "」の使いわけに注意して下さい。

やはり長いので、ファイルに保存して、コマンドにしておくことをお勧めします。

#! /bin/bash
bash -c "sleep 5; test -e /proc/$$ && kill -KILL $$" >/dev/null &
disown $!
exec cat -n /dev/stdin

こんなかんじのシェルスクリプトを、automatic_shutoff という名前で用意したとすれば、

上の例は

hoge_command |automatic_shutoff |less

となります。

id:logihot

ありがとうございます。試して見ます!

2010/02/11 15:17:07
id:mjy No.13

回答回数70ベストアンサー獲得回数22

ポイント16pt

前回の回答にはちょっと無駄がありました。

こちらのほうがいいです。

hoge_command の出力を less で受け取るワンライナー

bash -c 'bash -c "sleep 5; test -e /proc/$$ && kill -KILL $$" >/dev/null & disown $!; exec ./hoge_command' |less

シェルスクリプトにするならば、下のようになる。

#! /bin/bash
bash -c "sleep 5; test -e /proc/$$ && kill -KILL $$" >/dev/null &
disown $!
exec "$@"

スクリプトに automatic_shutoff と名付けたならば、

このように実行する。

automatic_shutoff hoge_command |less
id:logihot

試させて頂いたところ、見事に成功しました!深く感謝します。

正常の場合は、即時結果が返り

不良の場合は、5秒後に処理を強制終了して返りました

他の方の場合は、正常時も5秒間waitする必要があったのですが、上記コードが正常時にwaitする必要なく即時結果が返る理由は、どの部分にあるのでしょうか?

2010/02/12 19:00:28

質問者が未読の回答一覧

 回答者回答受取ベストアンサー回答時間
1 jp---jp 41 16 1 2010-02-11 11:38:16
2 jp---jp 41 16 1 2010-02-11 11:40:43
3 いわわ 101 89 10 2010-02-15 16:09:22
  • id:dev_zer0
    > 実行するコマンドの出力結果
    ならば
    nkf hoge.txt | tee /dev/null & ( sleep 5 ; pkill nkf )
    とすれば標準出力にも出せます
    結果をファイルに落としたい場合は/dev/nullを適当なファイル名にしてください
  • id:longicorn
    > 実行するコマンドの出力結果
    これはリダイレクトを使用する等の方法を取れば良いだけなので、
    バックグラウンドに回すジョブ側でログを取り、あとは上記の各回答通りにすれば良いでしょう。

    例えばこんな感じにすればよいです。
    sh "grep -r hoge /etc > /tm/grep.log &"; sleep 5; kill -kill grep
  • id:logihot
    皆様有り難う御座います。説明不足が多く申し訳御座いません。

    正常な場合は、即時結果が知りたく、異常な場合は、5秒後にエラーを通知したいです。

    つまり、正常な場合は、5秒待たずに結果だけを先に出力して、処理を終わらせるか、kill部分をバックグランドに渡したいです。

    PHPからコマンドを呼び出すのですが、正常な場合は即時結果が欲しく、異常な場合でも5秒以内には結果が欲しいため、このような質問をさせて頂きました。

    頂いた方法ですと、どうしても結果を得るまでに5秒かかってしまい、異常な場合は対応できるのですが、正常パターンで即時結果だけ欲しい部分が何とかならないかと悩んでおります。
  • id:longicorn
    >PHPからコマンドを呼び出すのですが
    こういう情報は先に出しておけば各回答者の回答は変わってきたはずです。

    こういった場合ならば、PHPで対応すべきでむしろスクリプトのみで対応する方法は不自然だと思います。

    PHPは自分は触ったことは無いですが、基本的に普通のスクリプト言語のはずですのでいくらでも対処方法はあるかと思います。
    PHPで少し調べて考えただけでも、
    例えば、popen、readで結果を取得しながら時間を計測し5秒を越えればpcloseするとか。
    stream_selectを使えばタイムアウト時間が指定できるので、シンプルに作れそうです。
  • id:dev_zer0
    > 正常な場合は、即時結果が知りたく、異常な場合は、5秒後にエラーを通知したいです。
    コマンド「だけ」だと多分無理
    タイマーを使ったプログラムを作る必要がある
  • id:daginn
    もし自由にパッケージの追加ができる環境でしたら、timelimitパッケージを利用する方法があります。
    http://devel.ringlet.net/sysutils/timelimit/
    一定の時間内に指定したコマンドが終了しないと,プロセスを終了しエラーステータスを返します。
    時間内に終了すればその場でプロセスが終了し、ステータス0を返します

    これを利用して、時間内にコマンドが終わらないと結果が出ないようにするには、
    tmpに実行結果を書き込んでおいて正常時だけ表示するようtmpを用意し、以下のようにすればよいと思います

    $ if (timelimit -q -s 9 -t 5 command > tmp); then cat tmp; else echo "ERROR"; fi; rm tmp
    (-q : 終了時 timelimitがだすメッセージを表示しない、 -t 制限時間、 -q 時間オーバーの時送るシグナル、SIGKILLとして9を指定)

    実行例
    $ if (timelimit -q -s 9 -t 5 echo "aaa" > tmp); then cat tmp; else echo "ERROR"; fi; rm tmp
    $ if (timelimit -q -s 9 -t 5 yes > tmp); then cat tmp; else echo "ERROR"; fi; rm tmp
    前者はすぐ aaa が表示され、後者は5秒後"ERROR"とでます。
  • id:tobeoscontinue
    http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230911/
    コマンドに割り当てる資源を制限する
    ulimit -t5
    ではどうでしょう。
    CPU時間なのでもっと小さくしたほうがいいかもしれません。
  • id:mjy

    > 上記コードが正常時にwaitする必要なく即時結果が返る理由は、どの部分にあるのでしょうか?

    5秒後に kill するという処理を子プロセスにまかせ、
    親はすぐに本来の処理を始めます。
    このさい重要な点は、以下の二つです。

    1. 子プロセスをバックグラウンドで実行すること
    コマンドに & を付けます。

    2. 子プロセスの出力が親の出力と混ざらないようにすること
    >/dev/null とでもしておきます。

    子プロセスが何も出力しないとしても、これは必要です。
    これを忘れると、 親プロセスの終了後も子プロセスが生きている場合、
    出力が閉じられないため、出力を受け取るコマンドが子プロセスの終了
    まで、出力を待ちつづけることになります。



    追記
    PHP から呼びだすということで、大変そうですが色々やり方はあると思いますので、
    がんばって下さい。
    下は参考に。


    # 前回の回答でもまだ無駄というか、なくても動く部分があるので、短かくできます。これで動くはずです。
    #! /bin/sh
    sh -c "sleep 5; kill -KILL $$" >/dev/null 2>&1 &
    exec "$@"

    # 上記ワンライナー版
    sh -c 'sh -c "sleep 5; kill -KILL $$" >/dev/null 2>&1 & exec hoge_command'


    # いきなり kill -KILL するのは乱暴なので、こうするのもあり
    #! /bin/sh
    sh -c "sleep 5; kill $$; sleep 0.5; kill -KILL $$" >/dev/null 2>&1 &
    exec "$@"

    # 上記ワンライナー版
    sh -c 'sh -c "sleep 5; kill $$; sleep 0.5; kill -KILL $$" >/dev/null 2>&1 & exec hoge_command'

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません