golang gotchas #3 executing os commands

Ever thought of executing an OS command within golang? Rarely suppose, but there are such scenarios. In this gotcha, we would be running a simple file logger and verify whether the logger is operating correctly by checking the number of lines logged within a unit test.

Hm… you might say “why don’t we just write a function to read that log file and do the line counts?” YES~ indeed that is a developer’s way to handle the verification and works perfectly fine for such an EASY scenario, however, if we are handling much COMPLEX scenarios such as acquiring os / file level information, it would be better to execute the OS commands directly.

PS. source code available at https://github.com/quoeamaster/golang_blogs/tree/master/2021-11-gg-os-cmds

run the command in the EASY way

The most straightforward way is to use “exec.Command()”:

since we just want to know how many lines of logs had been appended; running “wc -l {file}” will do the trick. The “exec.Comamnd()” is super handy as we just need to supply the command’s name and then the necessary arguments and flags to run. Results of the execution could be accessed through the command’s Output().

gotcha~ the path for accessing your targeted command

For most cases, our targeted command would be on “/usr/bin/” (linux and mac), but if your command is a non standard one which you installed by yourself, then the full path to the command SHOULD be provided instead.

Take an example:

  • wc — assumes command available at /usr/bin/wc
  • /devevlopment/bin/wc — assumes this “wc” command is a special one and lives under the “/development/bin/” folder. This is an example of a full path.

run the Command in a FLEXIBLE way

Um… whenever we say “flexible”, the other name is “complex” :))))

Now we would be using the same “exec” package, but through creating the “exec.Cmd” object:

exec.Cmd provides various configurations to run the targeted os command, suggested configurations would be following:

  • Path — where the targeted os command is located, again full path might be required if the command is NOT located in the standard locations.
  • Args — additional flags and arguments to run the command. Optional.
  • Env — environment variables to support the command. Assume the command’s behaviour would be affected by an environment variable’s value, the way to set the variable is through “Env” in a string format “key=value”.
  • Stdxxx — if the result of the execution is important; then setting such configurations would be necessary.

In the above code snippet; Path is set to /usr/bin/wc, Env is set to “PATH=/usr/bin/|”. Finally call “run()” to execute the os command. Since we have also set the Stdout and Stderr to a StringBuffer, the corresponding results could be accessed through “String()”.

gotcha~ the tricky Args configuration

For most cases, running os commands required some additional flags or arguments; hence setting such info through Args is inevitable. In the code snippet above, the settings is an array of strings (depicting either flags or arguments required)… somehow the weird part is the 1st argument which is actually a non-sense value “NOT_USED_:)”. The fact is the 1st argument is expected to be the os command’s name; hence it is omitted in the execution, which means if we are going to run “wc -l {file}, the array should be [“wc”, “-l”, “{file}”], as explained the 1st argument would be omitted; hence you can replace it with any value → [“NOT_USED_:)”, “-l”, “{file}”]

now then… if Args was set to [“-l”, “{file}”]; the result equals to running the os command “wc {file}”, hence the output would be quite different.

closings

Usually we would just code out everything for our projects, but there might be times when we want to have a quick-n-easy way to perform tasks without additional coding (especially when your schedule is like hell); hence learning how to execute os commands would be effective. Some possible scenarios I could think of at the meantime:

  • delete test files
  • run testing tools which is not directly supported by CI platforms
  • packaging and bundling the executables in a non standard way (e.g. use self writen shell scripts)

Congratulations~ As you have just equipped another tool in your belt.

:)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
devops terminal

devops terminal

a java / golang / flutter developer, a big data scientist, a father :)