if
statements with square brackets. Later, I learned that square brackets are only sometimes (or almost never) necessary.Square brackets are just a shorthand form of the
test
command, and if
just evaluates whether the expression/command that follows it returns a 0.But commands' return values aren't displayed anywhere in plain sight, so then I learned about the special variable
$?
, which stores the return value of the previous command.Basically, if you're using
grep
to determine whether or not something exists, wrapping it with the test
command is unnecessary. grep
already returns a 0 when it finds something, and it returns something else when it doesn't. Negating the return value of a grep
command only requires that you prepend an exclamation point to the whole thing.See example below for what I'm talking about. No square brackets anywhere in the if statements, because all I'm testing for is presence or absence of certain strings. Oh, and I wrote the script so Visual Studio Code could use flow from a docker container.
It was balking at my usual script containing just
#!/bin/bash docker run --rm -v "$PWD":/src -w /src [image]:[version] [command] $*which I used for lying that I had Golang installed on the system (where
image
and version
were the name and version of a docker image derived from golang:1.9) and [command] was one of the commands Visual Studio Code was complaining about not having (and were contained in the docker image):
go-outline: go get -u -v github.com/ramya-rao-a/go-outline go-symbols: go get -u -v github.com/acroca/go-symbols gocode: go get -u -v github.com/nsf/gocode godef: go get -u -v github.com/rogpeppe/godef godoc: go get -u -v golang.org/x/tools/cmd/godoc gogetdoc: go get -u -v github.com/zmb3/gogetdoc golint: go get -u -v github.com/golang/lint/golint gomodifytags: go get -u -v github.com/fatih/gomodifytags gopkgs: go get -u -v github.com/uudashr/gopkgs/cmd/gopkgs gorename: go get -u -v golang.org/x/tools/cmd/gorename goreturns: go get -u -v sourcegraph.com/sqs/goreturns gotests: go get -u -v github.com/cweill/gotests/... guru: go get -u -v golang.org/x/tools/cmd/guru impl: go get -u -v github.com/josharian/impl go play: go get -u -v github.com/haya14busa/goplay/cmd/goplayThere was one more that was not in that list that I also had to install, but I don't remember what it was. I can post the Dockerfile for the image later. Anyway, knowing about
$?
is also helpful for figuring out how you want to structure commands within if statements.
#!/bin/bash LOG_FILE=/home/dogi/flow_log function run_flow { echo "Creating flow container" >> $LOG_FILE docker run -dti --name "flow_server" -v "$PWD":"$PWD" -w "$PWD" vscode-node:8 bash } function start_flow { # Don't let crazy process spawners try to spawn flow repeatedly if docker ps -a | grep flow_server | grep seconds; then echo "Wait a minute" >> $LOG_FILE echo "`docker ps -a`" >> $LOG_FILE return fi # Run the flow container if it doesn't exist already. if ! docker ps -a | grep flow_server; then echo "Flow container doesn't exist; creating" >> $LOG_FILE echo "`docker ps -a`" >> $LOG_FILE run_flow # If the flow container exists, but was started in a different directory # (i.e., not found in mounts), destroy it and create it in the current one. elif ! echo $(docker inspect -f '{{ .Mounts }}' flow_server) | grep -w "$PWD "; then echo "Flow container has wrong mounts" >> $LOG_FILE echo "`docker inspect -f '{{ .Mounts }}' flow_server`" >> $LOG_FILE if docker ps -a | grep Up | grep flow_server; then echo "Flow container is running; killing" >> $LOG_FILE echo "`docker ps -a`" >> $LOG_FILE docker kill flow_server fi if docker ps -a | grep flow_server; then echo "Flow container exists; deleting" >> $LOG_FILE echo "`docker ps -a`" >> $LOG_FILE docker rm flow_server fi run_flow # Run the flow container if it already exists and was started in the current # directory elif ! docker ps -a | grep Up | grep flow_server; then echo "Flow container exists in the proper directory but isn't running; restarting container" >> $LOG_FILE echo "`docker ps -a`" >> $LOG_FILE docker start flow_server fi } # Suppress docker output. VS Code just wants flow's output. start_flow > /dev/null docker exec -i flow_server flow $*