我需要将各种文件复制到各种文件夹中。我可以将所有复制命令添加到bash脚本中,然后运行该脚本,但是如果要向该复制“队列”添加更多命令,则必须等到它完成。
有什么方法可以将命令作为队列运行,以及在事物运行时向该队列添加更多命令?
用不同的方式解释,我想开始一个长期运行的任务。在运行时,我要启动另一个直到第一个完成后才真正启动的启动。然后在最后一个之后添加另一个,依此类推。这有可能吗?
我需要将各种文件复制到各种文件夹中。我可以将所有复制命令添加到bash脚本中,然后运行该脚本,但是如果要向该复制“队列”添加更多命令,则必须等到它完成。
有什么方法可以将命令作为队列运行,以及在事物运行时向该队列添加更多命令?
用不同的方式解释,我想开始一个长期运行的任务。在运行时,我要启动另一个直到第一个完成后才真正启动的启动。然后在最后一个之后添加另一个,依此类推。这有可能吗?
Answers:
该at
实用程序以在指定时间运行命令而闻名,它还具有队列功能,可以要求立即开始运行命令。它从标准输入读取要运行的命令。
echo 'command1 --option arg1 arg2' | at -q myqueue now
echo 'command2 ...' | at -q myqueue now
该batch
命令等价于at -q b -m now
(-m
意味着命令输出,如果有的话,将像cron一样邮寄给您)。并非所有的Unix变体都支持队列名称(-q myqueue
);您可能只限于一个名为的队列b
。Linux at
仅限于单字母队列名称。
now
,不是-t now
,抱歉。我没有注意到示例代码中的错误。
附加&
到命令的末尾以将其发送到后台,然后wait
在运行下一个命令之前将其发送到后台。例如:
$ command1 &
$ wait; command2 &
$ wait; command3 &
$ ...
wait
?我所有的杀手似乎都无法渗透。
wait
直到以前的完成只是停止作业。
nohup
吗?
布拉德和曼科夫的解决方案都是不错的建议。类似于两者结合的另一个方法是使用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 shell中后将对其进行解释。使用“ CTL-V”获得该序列。
制作一些简单的shell脚本以使其自动化并使命令排队很容易。然后,每当您要检查后台队列的状态时,都可以通过以下方式重新连接:
screen -S queue -r
从技术上讲,您甚至不需要命名屏幕会话,它就可以正常工作,但是一旦您迷上了它,您将想要一直保持运行状态。;-)
当然,如果这样做,另一种好方法是将当前窗口之一命名为“ queue”并使用:
screen -S queue -p queue -X stuff "command"
对于您所描述的用例,我已经成功使用了一个实用程序。最近,我将我的主要笔记本电脑移至了新硬件,这涉及到将某些文件移至NAS,并将其余文件移至新计算机。
这就是我做的。
设置与网络连接有关的所有计算机,以便它们可以相互访问。
在要从中移动文件的计算机(以下称为源计算机)上,安装rsync和apt-get install rsync
和秘密保护的任务后台处理程序(网站http://vicerveza.homeunix.net/~viric/soft/ts/)。如果您在Debian上,则软件包名称为ts
is,task-spooler
并且将可执行文件重命名,tsp
以避免名称与软件包中的ts
可执行文件冲突moreutils
。通过网站链接的Debian软件包可以完美地安装在Ubuntu上dpkg -i task-spooler_0.7.3-1_amd64.deb
或类似版本上。
还要确保所有计算机都已通过SSH安装了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
然后在源计算机上打开一个终端,使用进行登录ssh target1
,照常进行身份验证,然后将该终端保持打开状态。请注意,有一个名为的套接字文件~/.ssh/master-user@target1:22
,该文件将保持已认证的主会话打开,并允许后续的无密码连接user
(只要连接使用相同的目标主机名和端口)。
此时,您需要验证您是否可以登录而不提示您对目标计算机进行身份验证。
现在运行ts rsync -ave ssh bigfile user@target1:
单个文件或ts rsync -ave ssh bigdir user@target1:
目录。使用rsync时,不要在目录中包含斜杠(bigdir
与相比bigdir/
),这一点很重要,否则rsync会假定您的意思与bigdir/*
大多数其他工具相同。
任务后台处理程序将返回提示,并让您连续将许多这些命令排队。检查ts
不带参数的运行队列。
Task Spooler具有许多功能,例如重新安排运行队列,仅在另一个作业成功运行时才运行特定作业等ts -h
。有时我会在运行时检查命令输出ts -c
。
还有其他方法可以执行此操作,但是对于您的用例,它们都包括Task Spooler。我选择在SSH上使用rsync来保留文件时间戳,而通过SMB复制则不会。
task-spooler
:-) 回答的部分内容丢失了。无论如何,这是您的意见中的一个很好的建议,我会尽快做的。
我也经常需要这样的东西。我编写了一个小实用程序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 ...
与其他方法相比,此方法的最大优点是不需要以任何特殊方式运行第一个作业,您可以在新作业中遵循任何流程。
您可以简单地将命令添加到已经在运行命令的Shell的命令行中。
仔细键入或在其他位置键入,验证并剪切并粘贴。即使当前命令正在输出行,您仍然可以键入新内容,然后按Enter键,并且在所有命令运行或输入完毕之前它将运行。
示例如下。您可以剪切并粘贴整个内容,也可以在第一个运行时(如果您输入的速度非常快)或在第二个运行时输入以下命令:
echo "foo"
sleep 10; echo "bar"
sleep 3
echo "baz"