キュー内でコマンドを実行する方法


42

さまざまなファイルをさまざまなフォルダーに大量にコピーする必要があります。すべてのコピーコマンドをbashスクリプトに追加して実行できますが、そのコピー「キュー」にさらにコマンドを追加する場合は、完了するまで待つ必要があります。

コマンドをキューとして実行し、実行中にそのキューにコマンドを追加する方法はありますか?

別の方法で説明すると、長時間実行するタスクを開始したいです。それが実行されている間、私は実際に最初のものが完了するまで開始しない別のものを開始したい。そして、最後の1つ後に別のものを追加します。これはどういうわけか可能ですか?


3
問題を解決する回答を受け入れることをお勧めします。あなたのために働くそれらのカップルがあるようです。
ホルム

2
はい、できます。問題は、Macを使用している会社で働いていたときにこれを尋ねたことです。私はそこで働いていませんし、自分でMacを持っているわけでもないので、これらをテストする方法はありません。実際に機能するかどうかをテストできないとき、答えとしてマークすることに不安を感じることはありません。そのため、「答え」がそのように現れるように、今のところ、人々は彼らがうまくいくと思う答えに投票することを望んでいます代わりに。
ヴィッシュ

回答:


25

at最高の指定した時刻にコマンドを実行するために知られているユーティリティは、また、キュー機能を持っており、今のコマンドの実行を開始するように要求することができます。コマンドを読み取り、標準入力から実行します。

echo 'command1 --option arg1 arg2' | at -q myqueue now
echo 'command2 ...' | at -q myqueue now

このbatchコマンドはat -q b -m now-mcronと同様に、コマンド出力があれば、メールで送信されます)と同等です。すべてのUNIXバリアントがキュー名(-q myqueue)をサポートしているわけではありません。という単一のキューに制限される場合がありますb。Linux atは、1文字のキュー名に制限されています。


2
少なくともLinuxでは、これは前のコマンドが完了するのを待つようには見えません。
wds

@wdsはDebian wheezyで動作します。どこで、どのように壊れたのですか?コマンドが完了するのを待つだけであることに注意してください。コマンドが親よりも長生きするサブプロセスを起動する場合、atはサブプロセスを待機しません。
ジル「SO-悪であるのをやめる」

CentOS 6で試してみました。単純な「sleep x」でテストしました。私はそれを実行するために何をするのか分かりませんが、サブシェルを開始し、そのサブシェルが結果を待つべきだと仮定します(スリープコールはすぐには戻りません)。
wds

キュー名だけでなく、「今」も標準ではありません
。ubuntuの

@winwaedああ、そうnowじゃない-t now、ごめんなさい。サンプルコードに間違いがあることに気づきませんでした。
ジル 'SO-悪である停止

23

&コマンドの最後に追加してバックグラウンドに送信し、次のコマンドをwait実行する前にコマンドを送信します。例えば:

$ command1 &
$ wait; command2 &
$ wait; command3 &
$ ...

2
わーい!あなたがオフに何かを蹴ったし、それの後に何かをキューにする方法をstackoverflowのを見て行きましたときに、この構文は素晴らしいです
エリックAronesty

2
その間にこれらのコマンドのいずれかに気が変わった場合、何を行うことができますwaitか?私のすべてのキルショットには影響されないようです。
ケンウィリアムズ

1
コマンドを強制終了するだけです。wait以前のものが終了するまで、単に仕事を停止します。
ゲルトソンダービー

これは動作しnohupますか?
マイケル

11

BradとMankoffのソリューションは両方とも良い提案です。両方の組み合わせに似ているもう1つの方法は、GNU Screenを使用してキューを実装することです。これには、バックグラウンドで実行できるという利点があり、いつでも確認でき、新しいコマンドをキューに入れると、前のコマンドが終了した後に実行されるようにバッファーに貼り付けられます。

ファーストラン:

$ screen -d -m -S queue

(偶然、素晴らしい。screenrcファイルで遊ぶのに今が良い時間です

これにより、キューという名前のバックグラウンドスクリーンセッションが生成されます。

ここで、好きなだけコマンドをキューに入れます:

screen -S queue -X stuff "echo first; sleep 4; echo second^M"

私はテストのために上記の複数のコマンドを実行しています。ユースケースはおそらく次のようになります。

screen -S queue -X stuff "echo first^M"
screen -S queue -X stuff "echo second^M"

上記の私の行の「^ M」は、スクリーンが既存のbashシェルにそれを詰め込んだ後に後で解釈される埋め込み改行を取得する方法であることに注意してください。「CTL-V」を使用して、そのシーケンスを取得します。

それを自動化してコマンドをキューに入れるための簡単なシェルスクリプトを作成するのは非常に簡単です。その後、バックグラウンドキューのステータスを確認するたびに、次の方法で再接続します。

screen -S queue -r

技術的には、スクリーンセッションに名前を付ける必要さえなく、それはうまく機能しますが、一度それに夢中になれば、とにかく常に実行中のものを残したいと思うでしょう。;-)

もちろん、それを行う場合、別の良い方法は、現在のウィンドウの1つに「キュー」と名前を付けて使用することです。

screen -S queue -p queue -X stuff "command"

これは基本的に、実行中の画面セッションでコマンドを「タイプ」するだけで、最初のコマンドが終了した後にシェルが再び制御を取得すると、このコマンドが開始されるようです。言い換えると、@ mankoffのソリューションと同等ですが、入力を行うのに手の込んだツールを使用します。
ケンウィリアムズ

ほとんど-主な違いは、画面ソリューションがより良い自動化をサポートしていることです。いくつかの作業は手作業で、その他の作業はスクリプトで、すべてシンプルなインターフェースで行えます。
ヨルダン

@Jordan非常に良い、それは私のために働く。しかし、-Xの後の「もの」とは何ですか?
コンスタンチン

@Konstantin gnu.org/software/screen/manual/html_node/Paste.html#Paste(TL ; DR-入力したかのように端末に続くもの)
ヨルダン

@ジョルダンああ、私は今見ます。コマンドです。任意の文字列だと思いました。
コンスタンティン

8

あなたが説明しているユースケースのために私が大成功で使用したユーティリティがあります。最近、プライマリラップトップを新しいハードウェアに移動しました。これには、一部のファイルをNASに移動し、残りのファイルを新しいマシンに移動する必要がありました。

これは私がやった方法です。

  1. ネットワーク接続に関係するすべてのマシンをセットアップして、互いに到達できるようにします。

  2. ファイルを移動するマシン(以降、ソースマシンと呼びます)で、rsync with apt-get install rsyncおよびsecret-sauce Task Spooler(Webサイトhttp://vicerveza.homeunix.net/~viric/soft/ts/)をインストールします。あなたがDebianの上にある場合のパッケージ名はtsあるtask-spoolerと実行をするために名前が変更されtspて衝突名前を避けるためtsの実行可能なmoreutilsパッケージ。WebサイトからリンクされたDebianパッケージは、Ubuntuに完全にインストールできますdpkg -i task-spooler_0.7.3-1_amd64.deb

  3. また、すべてのマシンにSSHがインストールされていることを確認してくださいapt-get install openssh-server。ソースマシンで、ターゲットマシンへのパスワードなしのログインを許可するようにSSHをセットアップする必要があります。最も使用する方法は、公開キー認証によるものですssh-agent(その例についてはhttps://www.google.se/search?q=ssh+public+key+authenticationを参照)が、私は時々より簡単な方法を使用しますパスワード認証も同様です。次をSSHクライアント構成に追加します(~/.ssh/configまたは/etc/ssh/ssh_config):

    Host *
         ControlMaster auto
         ControlPath ~/.ssh/master-%r@%h:%p
    

    次に、ソースマシンで1つのターミナルを開き、でログインしssh target1、通常どおり認証し、このターミナルを開いたままにします。という名前のソケットファイルがあることに注意してください~/.ssh/master-user@target1:22。これは、認証済みのマスターセッションを開いたままにして、以降のパスワードなしの接続を許可するファイルですuser(接続が同じターゲットホスト名とポートを使用する限り)。

    この時点で、ターゲットマシンへの認証を求められることなくログインできることを確認する必要があります。

  4. 次にts rsync -ave ssh bigfile user@target1:、単一のファイルまたはts rsync -ave ssh bigdir user@target1:ディレクトリに対して実行します。rsyncでは、ディレクトリに末尾のスラッシュを含めないことが重要です(にbigdir比べてbigdir/)。そうしないと、rsyncは、bigdir/*他のほとんどのツールと同等のものを意味すると想定します。

    タスクスプーラーはプロンプトを返し、これらのコマンドの多くを連続してキューに入れます。ts引数なしで実行キューを検査します。

タスクスプーラーには、実行キューの再配置、別のジョブが正常に実行された場合にのみ特定のジョブを実行するなど、多くの機能がありますts -h。ヘルプを表示します。で実行しているときにコマンド出力を検査することがありts -cます。

これを行う方法は他にもありますが、ユースケースにはすべてTask Spoolerが含まれます。SMBを介したコピーにはないファイルのタイムスタンプを保持するために、SSHを介したrsyncを使用することを選択します。


私が知らなかったあなたの答えをありがとうts、非常に強力で使いやすいようで、githubで自動化され、debianized されただけです。
アレックス14

@Alex私はあなたのフォークを見て、元のソースの自動化とdebian化に関して何が行われたかに特に興味がありました。手順1.で元のソースをインポートし、2。追加してコミットする新しいコミットを強制的にプッシュしますか?これは、ソースを参照する誰かが(より簡単に)元のソースへの追加を信頼するのに役立ちます。これは私がPPAなどからインストールしない数少ないパッケージの1つであるため、フォークを使用して自分でビルドするとよいでしょう。
ホルム14

私は眼鏡を交換しなければならないことを知っている、私は既存のあなたの答えの一部を失ったtask-spooler:-) ...とにかく、それはあなたのコメントに非常に良い提案です、私はすぐにやります。
アレックス14

プログレッシブコミットでリポジトリを完了、削除、および再作成しましたが、わずか数回のミス(プッシュ前にローカルコミットをさらに代謝する必要があります)
Alex

4

このようなものもかなり頻繁に必要です。after他のプロセスが終了するたびにコマンドを実行するという小さなユーティリティを作成しました。次のようになります。

#!/usr/bin/perl

my $pid = shift;
die "Usage: $0 <pid> <command...>" unless $pid =~ /^\d+$/ && @ARGV;

print STDERR "Queueing process $$ after process $pid\n";
sleep 1 while -e "/proc/$pid";
exec @ARGV;

その後、次のように実行します。

% command1 arg1 arg2 ...  # creates pid=2853
% after 2853 command2 arg1 arg2 ... # creates pid=9564
% after 9564 command3 arg1 arg2 ...

他のいくつかのアプローチに対するこれの大きな利点は、最初のジョブを特別な方法で実行する必要がなく、新しいジョブで任意のプロセスを実行できることです。


素敵なスクリプト@ken。あなたは時々これを必要とするように見えるので、私はタスクスプーラーを試してみることをお勧めしますが。私の答えをご覧ください。
ホルム

きれいに見えます、ありがとう。TSに欠けている1つのことは、TSの下で開始されなかったジョブをフォローする機能のようです。既存のプロセスが終了するのを待つだけの目的で、新しいTSジョブを開始できると思います。
ケンウィリアムズ

確かに。これは、ソリューションの有用な側面です。
ホルム

2

Command1 && Command2

  • 「&&」は、command1が戻りコード0で終了した後にのみcommand2が実行されることを意味します
  • 注:|| は、command1が0以外の戻りコードで終了した後にのみcommand2が実行されることを意味します

1

すでにコマンドを実行しているシェルのコマンドラインにコマンドを追加するだけです。

慎重に入力するか、別の場所に入力して確認し、カットアンドペーストします。現在のコマンドが出力の行を吐き出している場合でも、何か新しいものを入力してEnterキーを押すと、すべてのコマンドが完了する前に実行または入力されたときに実行されます。

次に例を示します。全体をカットアンドペーストするか、1番目のコマンドの実行中に後続のコマンドを入力するか(本当に高速で入力する場合)、または2番目のコマンドの実行中に入力する可能性が高くなります。

echo "foo"
sleep 10; echo "bar"
sleep 3
echo "baz"

0

私が考えることができる最もハックな方法は、/ tmp内の単純なロックファイルでキューの「状態」を維持することです。file1.shがcpコマンドを実行しているとき、ロックファイル(またはハードリンク)を/ tmpに保持します。完了したら、ファイルを消去します。他のすべてのスクリプトは、選択した命名スキームのロックファイルを/ tmpで探す必要があります。当然、これはあらゆる種類の障害の影響を受けますが、設定するのは簡単であり、bash内で完全に実行可能です。


それはあなたがニーズを実行するすべてのジョブがロックファイルを保持するように変更することを必要とし、知っている(またはパラメータとして受け入れる)する必要があるため、実際に使用することは困難どの使用にロックファイルを。可能な限り、ジョブの外部にキューイングを配置することをお勧めします。
ケンウィリアムズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.