I have a few trivial programs: `exists`, `allexist` and `filterstat` (the latter because it is equivalent to `files = filter(stat,glob("*"))` and similar -- it does not pass through unmatched wildcard names, unlike normal glob wildcard expansion. See below. ## Waiting for things ### Downloads Waiting for Chrome downloads to finish (though will stall if a download is interrupted and the `.crdownload` is not removed. ```bash while exists *.crdownload; do echo -ne "Waiting: $(date)\r"; sleep 1; done; echo ``` the `echo -ne` and `echo` at the end are only so that the text in the console changes so you know something's happenning. ### Processes and Jobs These are two Python scripts, `lwn` (launch with name) and `wfp` (wait for process). The former runs a Python process which uses `setproctitle` to assume the given name, and then launches the given command as a subprocess. The second does similarly, but waits for named processes to finish first. This means you can chain jobs by name as follows ```bash lwn MyJobName command args... & wfp SecondJob MyJobName command2 args... & wfp AnotherSecondJob MyJobName command3 args... & # will run in parallel with SecondJob, starting after MyJobName exits wfp SecondJob+AnotherSecondJob command4 args... # will wait for both SecondJob and AnotherSecondJob, then command4 will execute ``` Note that bad things may happen if you put `+` in a job name as `wfp` uses `+` as a delimiter to separate multiple job names. lwn: ```python #!/usr/bin/env python from setproctitle import setproctitle # python -m pip install setproctitle from subprocess import run import sys args = sys.argv[1:] if len(args) < 2: print(f"Not enough arguments") print(f"{sys.argv[0]} [ ...]") exit(1) title = args[0] if len(title) > 15: title = title[:15] print(f"Truncating title to '{title}'") setproctitle(args[0]) cmd = args[1:] exit(run(cmd).returncode) ``` wfp: ```python from time import sleep from sys import argv from datetime import datetime def now(fmt="%c"): return datetime.now().strftime(fmt) try: me, myname, targetname, *cmd = argv except ValueError: print(f"{argv[0]} [ ...]") exit(1) def truncname(x): if len(x) > 15: x = x[:15] print(f"Truncating proc name to '{x}'") return x targetnames = [truncname(x) for x in targetname.split("+")] setproctitle(myname) def pgreps(xs): return sum([pgrep(x) for x in xs],[]) while m := pgreps(targetnames): sleep(1) print(f"Waiting for {len(m)} process{'es' if len(m)>1 else ''}... {now()}",end="\r") print() if len(cmd) > 0: exit(run(cmd).returncode) else: exit(0) ``` ## exists, allexist and filterstat Perl makes such programs very short to write due to things like the assumed `$_` in things like `for(@ARGV)` which is equivalent to `for $_(@ARGV)` and basically is equivalent to e.g. `for $_ in @ARGV` in a language like Python. ### exists Returns true provided *at least one* of its arguments exists ```perl #!/usr/bin/env perl for(@ARGV) { exit(0) if -e; } exit(1) ``` ### allexist Returns true *unless at least one* of its arguments does not exist. (Note: it returns true if given no arguments, whereas `exists` returns false with no arguments.) ```perl #!/usr/bin/env perl for(@ARGV) { exit(1) unless -e ; } exit(0); ``` ### filterstat Returns arguments if and only if they exist (i.e. filters out non-existent files) ```perl #!/usr/bin/env perl for(@ARGV) { print "$_\n" if -e; } ```