Search code examples
shellsublimetext3gnu-makesublime-build

How to execute sub-shell commands in Sublime Text 3 build systems?


I am trying to write a generic build system for my C++ projects on a remote machine. The remote home directory ~/ is mounted on my local machine at /network/mountdir/ and my file_path=/network/mountdir/project_dir/file.cc corresponds to ~/project_dir/file.cc on the server. I wish to be able to use this build system regardless of which directory I am in on the same remote server.

For that purpose, I try something along the following lines.

"shell_cmd". : "ssh -tt server 'export TERM=xterm; cd' $(echo ${file_path} | cut -d'/' -f4-) '&& make'",
"shell"      : true,
"working_dir": "$file_path"

Unfortunately, this does not work. I get the following error.

shell_cmd or cmd is required
[cmd: None]

I figure this complaint is thrown because of the $(...) subshell. I am unable to figure out how to make this work. Kindly advise. Thanks.


Solution

  • Indeed your issue is that the $ is special in sublime-build files because it's used to denote variable expansions in the build system fields that support it, such as the ${file_path} that you're using to get the path of the current file.

    In the normal course of operations if you were to use a $ in front of text, Sublime treats it as a variable to expand, and any variables that have names that it doesn't understand get replaced with an empty string.

    So for example, something like this to echo your home directory won't work:

    "shell_cmd": "echo $HOME",
    

    Sublime sees $HOME as a variable, it doesn't know what that is so it expands it to an empty string, and the result is to just execute the echo command with no arguments.

    In order to tell Sublime that the $ in your command is meant to be a literal $ that it passes on to the shell, you need to quote it as \$; if Sublime sees that sequence, then it replaces \$ with $ and does nothing else, which lets the text pass through.

    However sublime-build files are JSON, and in JSON \$ is not a valid escape sequence, so doing this will stop the file from parsing as JSON, which will end you in a situation where you try to build and the status bar will say No build system because the file couldn't be loaded.

    So, taken all together the simple example here would need to look like this:

    "shell_cmd": "echo \\$HOME",
    

    Now when the file is loaded as JSON, the \\ is converted into a single character by the parser, leaving Sublime to see the \$ and handle it like you want.

    It's interesting to note in your case that using the $() syntax is actually triggering what may be a bug in Sublime, because it's actually causing the entire shell_cmd key to be set to an empty string, which makes the command that executes the build think the key isn't set and causes the error that you're seeing.