Skip to content

Calling Shell Commands from YAML

Wouldn't it be handy to get data from shell commands in YAML?

Well you can, and it's really easy.

YS has a bunch of functions in its Standard Library for calling shell commands, and passing data to and from them.

Let's take a look...

The shell function🔗

When you just want to run a shell command and let its outputs print to the terminal, you can use the shell function.

$ ys - <<'...'
!YS-v0
shell: 'fortune'
...
You have taken yourself too seriously.

This is the same as running fortune in from the command line.

You can also pass data to the shell command. Let's try the tac command, which reverses the lines of a file.

$ ys - <<'...'
!YS-v0
shell {:in "foo\nbar\nbaz\n"}: 'tac'
...
baz
bar
foo

The sh function🔗

The sh function doesn't print the output to the terminal. It returns a mapping that contains a bunch of fields like the exit code, stdout, stderr, and more.

$ ys - <<'...'
!YS-v0
result =:
  sh: 'echo "Hello, World!"'
say: result.out
...
Hello, World!

Let's look at the entire result object:

$ ys - <<'...'
!YS-v0
result =:
  sh: 'echo "Hello, World!"'
say: result
...
{:proc #object[java.lang.ProcessImpl 0x512d4b90 Process[pid=1364706, exitValue=0]], :exit 0, :in #object[java.lang.ProcessImpl$ProcessPipeOutputStream 0x22ebcf7e java.lang.ProcessImpl$ProcessPipeOutputStream@22ebcf7e], :out Hello, World!
, :err , :prev nil, :cmd [echo Hello, World!]}

That's kind of ugly and hard to read.

Let's use the yaml/dump function to pretty print it:

$ ys - <<'...'
!YS-v0
result =:
  sh: 'echo "Hello, World!"'
say: result:yaml/dump
...
proc: !!java.lang.ProcessImpl {}
exit: 0
in: !!java.lang.ProcessImpl$ProcessPipeOutputStream {}
out: |
  Hello, World!
err: ''
prev: null
cmd:
- echo
- Hello, World!

Much better!

You can also pass data to the sh function just like the shell function.

The sh-out function🔗

The sh-out function is like the sh function, but it returns the output as a string.

$ ys - <<'...'
!YS-v0
say:
  sh-out: 'echo "Hello, World!"'
...
Hello, World!

This handy shortcut is often just what the doctor ordered.

The bash function🔗

You can only run simple shell commands with the shell and sh functions.

In other words, you can't do things like pipes and redirects.

Of course you can also put any complicated shell command inside:

bash -c 'complicated | shell > command'

The bash function basically does this for you in YS code.

$ ys - <<'...'
!YS-v0
say:
  get _ :out:
    bash: 'fortune | tr a-z A-Z > /tmp/fortune.txt &&
           ls -l /tmp/fortune.txt && cat /tmp/fortune.txt'
...
-rw-r--r-- 1 ingy ingy 46 Jul 21 21:27 /tmp/fortune.txt
LOOK AFAR AND SEE THE END FROM THE BEGINNING.

The Shell's the Limit🔗

As you can imagine, there's no limit to what you can do with shell commands in YAML using YS.

Don't worry. Later we'll explore ways to actually limit capabilities in YS if you need to.

Comments