lang/bash/ RandomScripts


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.

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

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:

#!/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]} <process name> <command> [<args> ...]")
  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:

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]} <myname> <target_name> <cmd> [<args> ...]")
  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

#!/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.)

#!/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)

#!/usr/bin/env perl
for(@ARGV) { print "$_\n" if -e; }