Sometimes shell is really the best even for complex stuff - for the example in initrd or during machine provisioning - but in most cases, having any sort of non-trivial flow control in shell is a bad idea.
Sometimes shell is really the best even for complex stuff - for the example in initrd or during machine provisioning - but in most cases, having any sort of non-trivial flow control in shell is a bad idea.
It is often a bad idea in other programming languages also. Yet, some complex control flow constructs are straigthforward in shell but very difficult in other languages. How do you
ls *.jpg | grep 2019 | while read x ; do
echo convert ... $x album/$x
done | xargs -L 1 -P 32
in javascript or python, for example?How do you write in a normal language? With roughly 3 times the amount of keystrokes, but in a much more robust way. And if something fails, you will actually get a Python exception.
Your example does have some quoting problems which is understandable / common, but in Oil the obvious way should be the right way. That's not true in shell!
https://news.ycombinator.com/item?id=22161847
Thanks again for the encouragement!
files = [f for f in glob("*.jpg") if "2019" in f]
commands = ["convert ... {} album/{}".format(f) for f in files]
subprocess.run("xargs -L 1 -P 32".split(), input=os.fsencode("\n".join(commands)))
Note that this code, as well as original shell version, breaks if the filenames contains spaces or quotes; this is trivial to fix in python, but hard to fix in bash. for f in ./*2019*.jpg ; do
convert "$f" album/"$f" # just don't use xargs
done
Note the prepended ./ which is necessary if you want to protect against filenames that look like command line switches (a file named "-rf" can be pretty dangerous)If you wanted to use xargs and still make it perfectly safe with regards to spaces and quoting, you could use a GNU extension:
find . -maxdepth 1 -name '*2019*.jpg' -print0 | xargs -0 convertalbum.sh
# convertalbum.sh
convert "$1" album/"$1"
find prints the files terminated by ASCII NUL characters, xargs can understand this format if you give it the -0 option.There are still problems around detecting errors in pipes, though.
the whole point of my example was to show how easy parallelism is. You create a list of tasks, then you pipe the list to xargs or gnu parallel.
So, no, it's not easy, at least not if you want to handle all cases without wreaking havoc.
However I won't claim it's pretty or easy for people to use, so the point of Oil is basically to clean up patterns like this, e.g. find -print0 | xargs -0 and more.
This post uses a related problem and solution as design motivation for Oil:
How to Quickly and Correctly Generate a Git Log in HTML
Your code sort of cheats, since it is calling xargs to do the parallelism. Also, it is missing the imports. The equivalent pure python version will be probably still more complicated (regardless of it working for general filenames or not).
This is the whole point though -- you can still invoke external binaries in python!
For example, if you need to sort 100GB file, direct Python approach will likely OOM... while /usr/bin/sort will work just fine. I have seen people use this as an excuse ("I cannot use python's sort(), so I will just rewrite everything in shell") -- but for a complex script, it is almost always better to use Python as much as possible.