Suppose you know a scripting language (Perl, Python, Ruby, etc) and you’d rather not learn shell scripting (bash, PowerShell, batch, etc.). Or maybe you know shell scripting on one platform and don’t want to take the time right now to learn shell scripting on another platform. For example, maybe you know bash on Linux but don’t want to learn PowerShell on Windows, or vice versa.
One strategy would be to use your preferred language to generate shell scripts. Shell scripts are trivial when they’re just a list of commands: do this, do this, do this, etc. Where shell scripting gets more complicated is when you have variables, branching logic, library calls, all the stuff you already know how to do in another language. Maybe you could do all the complicated logic in your “native language” and just generate a shell script that’s simply as list of instructions with no other logic.
Another strategy is to make system calls from your preferred language. Most scripting languages have a system()
function that takes a string and executes it as a system command. The advantage of this approach is that it could have conditional logic that the code generation approach could not handle. The disadvantage is that you have to sort out what process the system()
call is running under etc.
Maybe you want to learn shell scripting, but you need to get work done now that you don’t yet know how to do. One of these strategies could buy you some time. You might transition, for example, from Python to PowerShell by generating more sophisticated shell scripts over time and writing simpler generator code until you just write scripts directly.
My work straddles Windows, Linux, Embedded, and I’m constantly struggling with how to create scripts needed for workflow that can be reused across platforms. For Windows and Linux, I’ve often settled on using gawk. Gawk is universally available on Linux, and (for now) trivially installed on Windows by placing a suitable executable in a path, and it has the system() function.
Of course, this mainly works when performing what is essentially file processing. Anything more operating system specific, well, there’s not much point in trying to create a cross platform script at that point.
Generating a shell script seems to be very complicated/brittle compared to just running a bunch of system() calls from a language like Ruby/Python/Perl.
I will often take a bash script then rewrite it in Python once it gets any kind of complicated logic or hits something like 100 lines, first by wrapping up a bunch of things in system/commands.getouput, and then later maybe implementing some of the logic in Python.
Python has a complete enough standard library that you could write everything in a cross platform manner and run the same script on Windows. You should never have to invoke system(). Or are you doing something that is truly platform-specific?
The single primary reason for the invention of Perl was to reduce the use of sh. A decade ago I used Perl as a kind of cross-platform sh. It wasn’t a perfect abstraction, of course (very Unix-oriented), but helped a lot. Nowadays, as mentioned, you can sort of do this with most languages. For example, right now I am using the sys.process standard library for Scala to create pipelines and the like calling out to Ruby, Python, and Perl programs that I did not write.
bash is a horrible language for anything non-trivial. That said, I’ve tried writing scripts in python, and I don’t think it’s as easy as it could be (I’m talking about subprocess, part of the standard library). Perl might be a good alternative? How is ruby for shell-scripting?
I’ll second Perl as the Lingua Franca of scripting-that-often-needs-to-execute-commands. It has the backtick notation you use in bash anyway:
http://www.perlhowto.com/executing_external_commands
$result = `somecmd -a foo -b bar`;
Also, easy integration with the shell with stdin and stdout.