9 个版本 (5 个破坏性更新)

使用旧的 Rust 2015

0.6.1 2019年2月8日
0.6.0 2019年2月4日
0.5.0 2019年1月31日
0.4.0 2018年10月1日
0.1.0 2018年5月18日

#2663命令行工具

每月 30 次下载

MIT 许可证

25KB
284

Logo, with help from Linn Kristiansen

loop 构建状态 crates.io

"UNIX 缺失的 loop 命令!"

loop 允许你在最喜欢的 shell 中编写强大、直观的循环单行命令!最后,Bash 中有意义的循环!

为什么?

bash 中的循环非常复杂和反复无常!我希望有一个简单直观的方式来编写可控制的循环,

  • 在可控制的 定时器 上运行!

    • $loop'ls' --every10s
  • 自定义计数器

    • $loop'touch $COUNT.txt' --count-by 5
  • 循环 直到输出匹配 条件!

    • $loop --until-contains 200 --./get_response_code.sh --site mysite.biz
  • 循环 直到一定时间

    • $loop'./poke_server' --for-duration8h
  • 循环 直到程序成功(或失败!)

    • $loop'./poke_server' --until-success
  • 遍历 标准输入

    • $cat files_to_create.txt | loop 'touch $ITEM'
  • 获取运行 摘要

    • $loop'ls' --for-duration10min --summary
  • 运行直到输出在调用之间 更改或保持不变

    • $loop --until-changesdate +%s
    • $loop --until-samedate +%s
  • 等等 更多!

因此 loop 应运而生!

安装

Linux

loop 可在 Snapcraft 中以 loop-rs 的形式用于所有发行版。

$ snap install loop-rs --beta

与该软件包相关的问题在此 跟踪

还有适用于Arch Linux用户的AUR,但我不维护它,所以请自行承担风险使用。

$ yaourt -S loop

OSX

如果您是Homebrew用户

$ brew tap miserlou/loop https://github.com/Miserlou/Loop.git
$ brew install loop --HEAD

Rust 用户

$ cargo install loop-rs

构建

$ cargo build
./debug/loop
$ cargo run 'echo $COUNT'
1
2
[ .. ]

用法

没有参数时,loop会尽可能快速地重复执行命令字符串,直到按下^C(Ctrl + C)。

$ loop 'echo hello'
hello
hello
hello
hello
[ .. ]

您也可以使用双横线(--)来分隔参数。

$ loop -- echo hello
hello
hello
hello
hello
[ .. ]

计数器

loop会将计数器的值放入$COUNT环境变量中。

$ loop 'echo $COUNT'
0
1
2
[ .. ]

可以通过--count-by更改计数器递增的量。

$ loop 'echo $COUNT' --count-by 2
0
2
4
6
[ .. ]

可以通过--offset偏移计数器。

$ loop 'echo $COUNT' --count-by 2 --offset 10
10
12
14
[ .. ]

迭代器也可以是浮点数!

$ loop 'echo $COUNT' --count-by 1.1
0
1.1
2.2
[ .. ]

还有$ACTUALCOUNT

$ loop 'echo $COUNT $ACTUALCOUNT' --count-by 2
0 0
2 1
4 2
[ .. ]

使用--summary可以获取成功和失败的总结(基于退出代码)。

$ loop 'echo $COUNT' --num 3 --summary
0
1
2
Total runs:  3
Successes:   3
Failures:    0

或者

$ loop 'ls -foobarbatz' --num 3 --summary
[ .. ]
Total runs:  3
Successes:   0
Failures:    3 (-1, -1, -1)

如果您只想获取最后一个结果,可以使用--only-last

$ loop 'echo $COUNT' --count-by 2 --num 50 --offset 2 --only-last # Counting is 0-indexed
100

计时循环

循环可以设置为定时器,该定时器接受从微秒到年份的人性化时间,使用--every

$ loop 'date' --every 5s
Thu May 17 10:51:03 EDT 2018
Thu May 17 10:51:08 EDT 2018
Thu May 17 10:51:13 EDT 2018

循环可以使用--for-duration限制为特定时长。

$ loop 'date' --for-duration 8s --every 2s
Fri May 25 16:46:42 EDT 2018
Fri May 25 16:46:44 EDT 2018
Fri May 25 16:46:46 EDT 2018
Fri May 25 16:46:48 EDT 2018
$

或者直到某个日期/时间,使用--until-time

$ loop 'date -u' --until-time '2018-05-25 20:50:00' --every 5s
Fri May 25 20:49:49 UTC 2018
Fri May 25 20:49:54 UTC 2018
Fri May 25 20:49:59 UTC 2018
$

直到条件

loop可以迭代,直到输出包含一个字符串,使用--until-contains

$ loop 'echo $RANDOM' --until-contains "666"
11235
35925
666
$ 

loop可以迭代,直到输出改变,使用--until-changes

$ loop --only-last --every 1s --until-changes -- 'date +%s' 
1548884135
$

loop可以迭代,直到输出保持不变,使用--until-same。例如,在用du监控下载或复制操作完成时很有用。

$ loop --every 1s --until-same -- 'du -bs .' 
236861997       .
$

或者直到程序成功,使用--until-success

$ loop 'if (( RANDOM % 2 )); then (echo "TRUE"; true); else (echo "FALSE"; false); fi' --until-success
FALSE
FALSE
TRUE
$

或者直到它失败,使用--until-error(也可以接受一个可选的错误代码)。

$ loop 'if (( RANDOM % 2 )); then (echo "TRUE"; true); else (echo "FALSE"; false); fi' --until-error
TRUE
TRUE
FALSE
$

或者直到它匹配正则表达式,使用--until-match

$ loop 'date' --until-match "(\d{4})"
Thu May 17 10:51:03 EDT 2018
$ 

遍历列表和标准输入

循环可以使用--for遍历所有类型的列表。

$ loop 'echo $ITEM' --for red,green,blue
red
green
blue
$ 

并且可以通过管道从标准输入读取。

$ cat /tmp/my-list-of-files-to-create.txt | loop 'touch $ITEM'
$ ls
hello.jpg 
goodbye.jpg

这可以与各种标志结合使用,例如--until-changes

$ printf "%s\n" 1 1 3 | loop --until-changes -- echo '$ITEM'
1
1
3

$ seq 10 | loop --until-changes -- echo '$ITEM'
1
2

您也可以轻松地将列表通过管道传递给loop

$ ls -1 | loop 'cp $ITEM $ITEM.bak'; ls
hello.jpg
hello.jpg.bak

或者通过键盘使用-i

$ loop 'echo $ITEM | tr a-z A-Z' -i
hello
world^D
HELLO
WORLD

--for可以接受所有类型的列表。

$ loop 'echo $ITEM' --for "`ls`"
Cargo.lock
Cargo.toml
README.md
src
target
$

有用的示例

以下是您可以用loop做的一些实用操作!

测试程序输入

如果您有很多文件和一个程序,但不知道哪个文件是程序所使用的,您可以循环遍历它们直到找到。

$ ls  -1 | loop './my_program $ITEM' --until-success;

或者,如果您有一份文件列表,但需要找到导致程序失败的文件。

$ ls  -1 | loop './my_program $ITEM' --until-fail;

等待网站上线

如果您刚刚启动了一个网站部署流程,您可能想在网站开始返回200响应代码时运行一个进程。使用--every--until-contains,您可以这样做而不使网站充斥着请求。

$ ./deploy.sh; loop 'curl -sw "%{http_code}" http://coolwebsite.biz' --every 5s --until-contains 200; ./announce_to_slack.sh

或者直到主机在线。

$ loop "ping -c 1 mysite.com" --until-success; ./do_next_thing

等待文件创建

如果您有一个长时间运行的过程,它会创建新文件,那么当该过程输出新文件时,您可能想启动另一个程序,如下所示

$ ./create_big_file -o my_big_file.bin; loop 'ls' --until-contains 'my_big_file.bin'; ./upload_big_file my_big_file.bin

为目录中的所有文件创建备份

如果您有一系列文件需要创建备份,您可以这样做

$ ls
hello.jpg
$ ls -1 | loop 'cp $ITEM $ITEM.bak'
$ ls
hello.jpg
hello.jpg.bak

尝试失败的脚本,直到它通过,最多 5 次

这是一个来自StackExchange的示例

我想在shell脚本中编写逻辑,使其在“status code=FAIL”的情况下重试运行,最多重试5次,每次重试间隔15秒。

StackExchange上有许多类似的问题,最终都以复杂的答案长线程结束。

使用loop,这是一个简单的单行命令

loop './do_thing.sh' --every 15s --until-success --num 5 

它将每15秒执行一次,直到成功,最多重试五次。

与 GNU Parallel 的比较

Reddit上的这个帖子,GNU Parallel作者Ole Tange在帖子中进行了loopparallel的有趣比较。

更多示例

有更多有用的示例吗?请发送一个pull request!

贡献

这个项目还比较年轻,所以还有很多工作要做。欢迎贡献!

在提交补丁之前,请先提交讨论的票据。pull requests应该针对master,如果合并,应该让Loop处于“可发货”状态。

如果您添加了大量的新代码,请在PR中包含一个功能测试。测试套件将在您打开pull request后由Travis CI运行。请将有关您的更改的GitHub问题或pull request URL作为代码中的注释(示例)。这将大大有助于项目的维护,因为它允许我们追踪用例并解释决策。同样,请确保您满足pull request模板中列出的所有要求。

请随意处理任何开放的票据,特别是任何标记有“help-wanted”标签的票据!

许可证

(c) Rich Jones, 2018-2019+. MIT License.

依赖项

~7–17MB
~231K SLoC