Using option flag with condition (shell script) - bash

I have this command inside my shell script file:
docker exec dev-wordpress $phpunitPath \
--configuration $configurationPath \
--testsuit $testsuit \
--group $group \
--testdox
It is working if I set the 'testsuit' and the 'group' as command line options.
The 'testsuit' and 'group' options should be used only if those variables has value.
Same issue with 'testdox' is solved with 'if-else' but it is not a good way when I want to do the same with 3 different options.
How can I avoid the '--group' option if I don't have value in $group variable?
#!/bin/zsh
phpunit="/var/www/html/wp-content/plugins/irea/api/src/vendor/bin/phpunit"
configuration="/var/www/html/wp-content/plugins/irea/api/tests/phpunit.xml"
testdox=
filter=
testsuite=
group=
while [ "$1" != "" ]; do
case $1 in
--group ) shift
group="--group $1"
;;
--testsuite ) shift
testsuite="--testsuite $1"
;;
--filter ) shift
filter="--filter $1"
;;
--testdox ) testdox="--testdox"
;;
esac
shift
done
docker exec irea-wordpress $phpunit \
--configuration $configuration \
$testsuite \
$group \
$filter \
$testdox

You can use parameter expansion :
docker exec dev-wordpress "$phpunitPath" \
--configuration "$configurationPath" \
${testsuit:+--testsuit "$testsuit"} \
${group:+--group "$group"} \
--testdox
This script should work well for $testsuit and $group.
I didn't notice you may have problem for the other two variable.
I updated the script, maybe you can try again.

I need to build up the command as a string first then run it with eval.
eval "docker exec irea-wordpress $phpunit --configuration $configuration $testsuite $group $filter $testdox"

Related

bash problem with single quotes expansion

I got the following script:
#!/usr/bin/env bash
# break on error
set -ex
## USAGE: ./open <type> <instance-name>
if [[ $# -ne 2 ]]; then
echo "## USAGE: ${0} <type> <instance-name>"
echo "type: team or project"
echo "instance-name: name of the instance to fetch the URL from"
exit 1
fi
ORGANIZATION="redacted_org"
PROJECT="redacted_project"
TYPE="redacted_type"
if [[ $1 == "team" ]]; then
TYPE="redacted_type_team"
fi
NAME=$2
BUILD_ID=$(az pipelines build definition list \
--organization "${ORGANIZATION}" \
--project "${PROJECT}" \
--query "\"[? contains(path, '\\\\stacks\\\\${TYPE}\\\\instances\\\\${NAME}') && name=='apply'].{id:id}\"" \
--output tsv)
echo "https://redacted_org.visualstudio.com/redacted_project/_build?definitionId=${BUILD_ID}"
The problem is that the BUILD_ID variable is being executed as (printed by the set -x):
++ az pipelines build definition list --organization redacted_org --project redacted_project --query '"[? contains(path, \'\''\\stacks\\redacted_type\\instances\\redacted_2\'\'') && name==\'\''apply\'\''].{id:id}"' --output tsv
Note the '" instead of " just after the --query parameter and in the end of it, and the \'\' everywhere I have a single quote instead of '
I need this BUILD_ID to be executed as follows, this command works fine when typed in the terminal itself:
$(az pipelines build definition list --organization "redacted_org" --project "redacted_project" --query "[? contains(path, '\\stacks\\redacted_type\\instances\\redacted_2') && name=='apply'].{id:id}" --output tsv)
What am I doing wrong?
In the stanza:
BUILD_ID=$(az pipelines build definition list \
--organization "${ORGANIZATION}" \
--project "${PROJECT}" \
--query "\"[? contains(path, \'\\\\stacks\\\\${TYPE}\\\\instances\\\\${NAME}\') && name==\'apply\'].{id:id}\"" \
--output tsv)
you've used some bizarre quoting. You want that to be just the way you expect:
BUILD_ID=$(az pipelines build definition list \
--organization "${ORGANIZATION}" \
--project "${PROJECT}" \
--query "[? contains(path, '\\stacks\\${TYPE}\\instances\\${NAME}) && name=='apply'].{id:id}" \
--output tsv)

Unable to execute command inside double square brackets inside my Makefile

clean:
#for container_name in ${NEW_DJANGO_IMAGE_NAME} \
${NEW_MSQL_IMAGE_NAME} \
${NEW_NGINX_IMAGE_NAME} \
${NEW_REDIS_IMAGE_NAME}; \
do if [[ 'a' == 'a' ]]; then echo 'fdfdf'; fi; done;
If I do something like this it works. Now instead of this silly line
do if [[ 'a' == 'a' ]]; then echo 'fdfdf'; fi; done;
I want to write the following:
do if [[ docker ps --filter "name=^/$$container_name$$" --format '{{.Names}}' == $$container_name ]]; then echo 'fdfdf'; fi; done;
The idea is that I iterate over a number of docker containers and if it happens that some of them are running I want to stop them. So in the place of echo 'fdfdf' I want to see this line: docker container stop <CONTAINER_NAME>;
Looks as simple as hell but I can't get it to work in the Makefile...What am I doing wrong?
You apparently think that [[ cmd == "string" ]] executes cmd before performing the test. This is not the case. Use:
[[ `cmd` == "string" ]]
instead. In your case it would look like this:
do if [[ `docker ps --filter "name=^/$$container_name$$" --format '{{.Names}}'` == $$container_name ]]; then docker container stop $$container_name; fi; done;
Or, a bit more readable, maybe:
IMAGES := $(NEW_DJANGO_IMAGE_NAME) $(NEW_MSQL_IMAGE_NAME) \
$(NEW_NGINX_IMAGE_NAME) $(NEW_REDIS_IMAGE_NAME)
clean:
#for cn in $(IMAGES); do \
tmp=`docker ps --filter "name=^/$$cn$$" --format '{{.Names}}'`; \
if [ -n "$$tmp" ]; then \
docker container stop $$cn; \
fi; \
done
Note that, in this last version, we use the bourne shell test commmand ([) instead of the bash-only conditional expression ([[...]]).

sh conditionally pass an option to command

I want to do something like:
#!/bin/sh
[ -f "/tmp/nodes" ]
[[ $? -eq 0 ]] && VAL=$? ||
geth --datadir /root/.ethereum \
${VAL+"--nodekey \"/root/nodekey.txt\""} \
--networkid 1999 \
--rpc \
--rpcaddr "0.0.0.0" \
I want the option --nodekey "/root/nodekey.txt" to be passed if the file /tmp/nodes exists. How can that be done more elegantly than an if with two nearly identical commands?
--EDIT--
This is the best I've been able to get working so far:
if [ $VAL -eq 0 ]; then
/geth --datadir /root/.ethereum \
--nodekey "/root/nodekey.txt" \
# No dice
# Would be nice if this worked so I didn't need the if
# ${VAL+ --nodekey "/root/nodekey.txt" } \
--networkid 1999 \
--rpc \
--rpcaddr "0.0.0.0"
else
/geth --datadir /root/.ethereum \
--networkid 1999 \
--rpc \
--rpcaddr "0.0.0.0" \
fi
This is another line in the file and works fine:
ENODE_URL=$(/geth --datadir /root/.ethereum ${VAL+ --nodekey "/root/nodekey.txt"} --exec "${JS}" console 2>/dev/null | sed -e 's/^"\(.*\)"$/\1/')
There's a bashism here, but it's [[ $? -eq 0 ]], as [[ is a ksh extension adopted by bash. There's no point to using $? at all here, since you can just directly perform your assignment based on whether the test -f succeeds:
touch /tmp/nodes # set us up for the truthy path
if test -f /tmp/nodes; then tmp_nodes_exists=1; else unset tmp_nodes_exists; fi
printf '%s\n' /tmp/nodes ${tmp_nodes_exists+"REALLY EXISTS" "(yes, really)"}
...properly emits as output (as run with dash, perhaps the most common minimal /bin/sh interpreter):
/tmp/nodes
REALLY EXISTS
(yes, really)
By contrast, to demonstrate that the other path fails as it should:
rm -f -- /tmp/nodes # set us up for the falsey path
if test -f /tmp/nodes; then tmp_nodes_exists=1; else unset tmp_nodes_exists; fi
printf '%s\n' /tmp/nodes ${tmp_nodes_exists+"REALLY EXISTS" "(yes, really)"}
emits as output only:
/tmp/nodes

Conditional in Docker argument in Bash

In my bash file I've something like this
docker run -d \
--network=host \
--name my-service \
--log-driver="$LOGGING" \
if [[ "$LOGGING" == 'splunk' ]]; then
echo "--log-opt tag={{.ImageName}}/{{.Name}}/{{.ID}} \\";
echo "--log-opt env=NODE_ENV \\";
fi
But shellcheck complains by showing the following result. Any idea?
https://github.com/koalaman/shellcheck/wiki/SC1089
Build the argument list first (in an array), then call docker. This has the additional benefit of getting rid of the ugly line continuation characters.
docker_opts=(
-d
--network=host
--name my-service
--log-driver="$LOGGING"
--log-opt="$log_opt"
)
if [[ $LOGGING == splunk ]]; then
docker_opts+=(
--log-opt "tag={{.ImageName}}/{{.Name}}/{{.ID}} \\"
--log-opt "env=NODE_ENV \\"
)
fi
docker run "${docker_opts[#]}"
The main idea, though, is to keep the conditional code as small as possible and keep it separate from the unconditional code.
I suggest to use $(if ..; then ...; fi):
docker run -d \
--network=host \
--name my-service \
--log-driver="$LOGGING" \
$(if [[ "$LOGGING" == 'splunk' ]]; then
echo "--log-opt tag={{.ImageName}}/{{.Name}}/{{.ID}}"
echo "--log-opt env=NODE_ENV"
fi)

Makefile multiline dash command run executable in a detached process

I have the following target in my makefile: (I'd like to run python http server in a detached process and when bash script is done kill the server)
TEST_PORT = 17777
test::
$(ENV_VARS) \
python -m SimpleHTTPServer $(TEST_PORT); \
PID=$$(lsof -t -i #localhost:$(TEST_PORT) -sTCP:listen); \
echo $(PID); \
if [ -n "$$PID" ]; \
then \
python test.py; \
fi; \
function finish { \
if [ -n "$$PID" ]; \
then \
kill -9 $$PID; \
fi \
} \
trap finish EXIT;
However when I put a & after the line python ... I get an error
/bin/dash: Syntax error: ";" unexpected
How can this be done in a proper way?
EDIT
I have changed my makefile to do the following:
test::
python -m SimpleHTTPServer $(TEST_PORT) &
PID=$$(lsof -t -i #localhost:$(TEST_PORT) -sTCP:listen); \
if [ -n "$$PID" ]; \
then \
$(ENV_VARS) python test.py; \
fi \
function finish { \
if [ -n "$$PID" ]; \
then \
kill -9 $$PID; \
fi \
} \
echo $$PID; \
trap finish EXIT;
However I am getting an error: (without the line number)
/bin/dash: Syntax error: word unexpected
The important thing to remember here is that your line breaks don't actually exist when the shell sees the command.
So your first command becomes:
$(ENV_VARS) python -m SimpleHTTPServer $(TEST_PORT); PID=$$(lsof -t -i #localhost:$(TEST_PORT) -sTCP:listen); echo $(PID); if [ -n "$$PID" ]; then python test.py; fi; function finish { if [ -n "$$PID" ]; then kill -9 $$PID; fi } trap finish EXIT;
And your second command becomes:
PID=$$(lsof -t -i #localhost:$(TEST_PORT) -sTCP:listen); if [ -n "$$PID" ]; then $(ENV_VARS) python test.py; fi function finish { if [ -n "$$PID" ]; then kill -9 $$PID; fi } echo $$PID; trap finish EXIT;
Now those are both very hard to read so I don't expect you to spot the problem but the problem is that you are missing statement terminators in a few places.
Specifically:
Braces ({}) are word elements and so need spaces around them (and a terminator before, and after, the closing brace). You are missing those terminators here fi } trap and here fi } echo.
fi is also not a statement terminator and so it needs one between it and the next statement. You are missing one here test.py; fi function (as well as the ones in the braces from the first point).

Resources