Correctly quote shell commands in Scala

(, en)

Once in a while you need to interact with the shell in Scala. This can be tricky, because the Scala standard library is confusing. I already have a post about running external processes in Scala. Sometimes you can’t prevent calling the shell or even building or templating shell scripts. For these cases it is paramount that you escape the input. In particular if you need to work with passwords, containing special characters, such as $ (dollar) or ' (the single quote).

This is an old problem, but I could not find anything useful for Scala. I know Python has the shlex module, including quote functionality. Better a good copy than a bad original.

import scala.util.matching.Regex

object ShUtil {
  // taken from python's shlex module
  // https://docs.python.org/3/library/shlex.html
  // https://github.com/python/cpython/blob/3.12/Lib/shlex.py#L323
  private val unsafeCharRegex: Regex = "[^\\w@%+=:,./-]".r

  def shQuote(s: String): String =
    if s.isEmpty then "''"
    else if unsafeCharRegex.findFirstIn(s).isEmpty then s
    else
      /*
        use single quotes, and put single quotes into double quotes
        the string ' is then quoted as "'"
       */
      "'" + s.replace("'", "'\"'\"'") + "'"
}

Nothing fancy here, just the same in a different language.

On the first sight it might look strange in the example test below:

it should "escape nested strings" in {
  val password = "s3'cr3t!"
  val cmd = s"echo ${shQuote(password)}"
  val shCmd = s"sh -c ${shQuote(cmd)}"
  // yes, it looks awful, but it's correct
  assert(shCmd == """sh -c 'echo '"'"'s3'"'"'"'"'"'"'"'"'cr3t!'"'"''""")
}

but it actually works very well.

Have fun.