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/goplay
There 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 $*