Comment by theamk
6 days ago
Note that at least in python, you can use "shlex.quote" instead - it's in stdlib and does not need any extra tools.
>>> import subprocess
>>> import shlex
>>> subprocess.run(['ssh', 'host', shlex.join(['ls', '-la', 'a filename with spaces'])])
ls: cannot access 'a filename with spaces': No such file or directory
works nested, too
>>> layer2 = ['ls', '-la', 'a filename with spaces']
>>> layer1 = ['ssh', 'host1', shlex.join(layer2)]
>>> layer0 = ['ssh', 'host0', shlex.join(layer1)]
>>> subprocess.run(layer0)
(I am not sure if Rust has equivalent, but if it does not, it's probably easy to implement.. Python version is only a few lines long)
Wrong! SSH is very much the worst: it uses the user's login shell, not sh -c. So if the user's login shell isn't POSIX compatible, it still fails!
Well, you gotta draw the line somewhere, right? You can ssh into all sort of weird places, like native windows machines, or routers which expose their own shell, and you cannot expect them to be as usable as the regular ones.
The systems with non-POSIX non-interactive shell are firmly in the "special" category. If a user decided to set their _non_interactive_ shell to fish - they know they are heading for trouble and should not be surprised. I would not worry about such users in my scripts for example.
Please correct me if I'm am wrong, but POSIX doesn't define a non-interactive or interactive shell, it only defines a login shell. You can't "set your non-interactive shell", only "set your login shell". OpenSSH could easily have decided to "join all arguments with spaces and pass them to sh -c", which would also have been a bad decision for the reasons listed in this article, but instead chose the even more esoteric choice of using the login shell, even when running non-interactive commands.
> I am not sure if Rust has equivalent
Not in the standard library, but there are packages.
This just confirms my habit of switching to python as soon as a shell script reaches any level of complexity