I have a bash script which opens Unity with arguments and builds a library:
#!/bin/bash
UNITY=$1/$2/Unity.app/Contents/MacOS/Unity
[ "$(uname -s)" == "Darwin" ] && $UNITY -buildtarget $3 -nographics -batchmode -upmNoDefaultPackages -serial $4 -username $5 -password $6
I run it like this:
./openUnity.sh $UNITY_EDITORS_PATH $UNITY_VERSION $PLATFORM $UNITY_LICENSE $UNITY_USERNAME $UNITY_PASSWORD
How can I add additional arguments to all content above?
What I would like is:
./openUnity.sh $LIST_OF_ARGS_ABOVE $NEW_ARGUMENTS
-testPlatform %testPlatform% \
-deviceType %deviceType% \
-closeAfterExecution \
-autoTestRun \
-killProcessesAfterExecution
I cannot really add indefinite number of arguments and finish with $20
Arguments need to be added like: ./script.sh $1 $2 due to external software - using Teamcity
Is there any good approach to do it?
If you truly need args passed to the script, then the only solution is to use location-specific arguments. I suspect that you can use the environment though, since that is a primary mechanic in CI, and it uses the existing environment values that are being passed to the script. The only requirement is that those env vars be exported, which is common practice in CI.
Doing things from the environment when possible is great in CI, and it will make this easier for you because it avoids extending the number of location-specific parameters up too high, and lets the script used named variables instead of variables with numeric names.
For your existing script can be refactored like so (I've prepended an echo so we can see what would be run):
$ cat openUnity.sh
#!/bin/bash
set -u # abort on unassigned variable
UNITY="${UNITY_EDITORS_PATH}/${UNITY_VERSION}/Unity.app/Contents/MacOS/Unity"
[[ "$(uname -s)" == "Darwin" ]] && \
echo "$UNITY" \
-buildtarget "$PLATFORM" \
-nographics \
-batchmode \
-upmNoDefaultPackages \
-serial "$UNITY_LICENSE" \
-username "$UNITY_USERNAME" \
-password "$UNITY_PASSWORD"
$ export UNITY_EDITORS_PATH
$ export UNITY_EDITORS_PATH=/Application/Unit.app
$ export UNITY_VERSION=20.0.1
$ export PLATFORM=darwin
$ export UNITY_LICENSE=abc123
$ export UNITY_USERNAME=dade_murphy
$ export UNITY_PASSWORD=hunter2
$ ./openUnity.sh
/Application/Unit.app/20.0.1/Unity.app/Contents/MacOS/Unity -buildtarget darwin -nographics -batchmode -upmNoDefaultPackages -serial abc123 -username dade_murphy -password hunter2
Now, if your additional parameters will always exist, then adding them is simple:
#!/bin/bash
set -u # abort on unassigned variable
UNITY="${UNITY_EDITORS_PATH}/${UNITY_VERSION}/Unity.app/Contents/MacOS/Unity"
[[ "$(uname -s)" == "Darwin" ]] && \
echo "$UNITY" \
-buildtarget "$PLATFORM" \
-nographics \
-batchmode \
-upmNoDefaultPackages \
-serial "$UNITY_LICENSE" \
-username "$UNITY_USERNAME" \
-password "$UNITY_PASSWORD" \
-testPlatform "$testPlatform" \
-deviceType "$deviceType" \
-closeAfterExecution \
-autoTestRun \
-killProcessesAfterExecution
However, if the new args are optional, we would have to conditionally build a set of args to append:
#!/bin/bash
set -u # abort on unassigned variable
# build an array of required args
args=(
-buildtarget "$PLATFORM"
-nographics
-batchmode
-upmNoDefaultPackages
-serial "$UNITY_LICENSE"
-username "$UNITY_USERNAME"
-password "$UNITY_PASSWORD"
-closeAfterExecution
-autoTestRun
-killProcessesAfterExecution
)
# append any optional args if they are found in the environment
[[ -n "${testPlatform}" ]] && args+=(-testPlatform "$testPlatform")
[[ -n "${deviceType}" ]] && args+=(-deviceType "$deviceType")
UNITY="${UNITY_EDITORS_PATH}/${UNITY_VERSION}/Unity.app/Contents/MacOS/Unity"
# Call UNITY and expand the 'args' array into arguments
[[ "$(uname -s)" == "Darwin" ]] && echo "$UNITY" "${args[#]}"
/Application/Unit.app/20.0.1/Unity.app/Contents/MacOS/Unity -buildtarget darwin -nographics -batchmode -upmNoDefaultPackages -serial abc123 -username dade_murphy -password hunter2 -closeAfterExecution -autoTestRun -killProcessesAfterExecution
$ export deviceType=microwave
$ export testPlatform=irix
$ ./openUnity.sh
/Application/Unit.app/20.0.1/Unity.app/Contents/MacOS/Unity -buildtarget darwin -nographics -batchmode -upmNoDefaultPackages -serial abc123 -username dade_murphy -password hunter2 -closeAfterExecution -autoTestRun -killProcessesAfterExecution -testPlatform irix -deviceType microwave
Related
fzf/ripgrep can search an alternate directory from the command line with something like.
rg something ./sompath | fzf
The fzf documentation has a nice little bash script for generating a preview of rg's results that I call with a shell alias and then open the file with vim:
#!/usr/bin/env bash
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
INITIAL_QUERY="${*:-}"
IFS=: read -ra selected < <(
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
fzf --ansi \
--color "hl:-1:underline,hl+:-1:underline:reverse" \
--disabled --query "$INITIAL_QUERY" \
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
--bind "alt-enter:unbind(change,alt-enter)+change-prompt(2. fzf> )+enable-search+clear-query" \
--prompt '1. ripgrep> ' \
--delimiter : \
--preview "$BAT_CMD --color=always {1} --highlight-line {2}" \
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
)
[ -n "${selected[0]}" ] && nvim "${selected[0]}" "+${selected[1]}"
It's very cool and works great. Unfortunately, there's no way to pass in a directory argument into this script. So you have to cd into the desired directory, do the search, and cd back.
Instead, I'd like to do something like this:
search_script initial_query ./some_dir
But my bash skills are weak and I'm not really sure what the best approach is for processing an optional directory argument.
The script has to somehow be smart enough to recognize when a directory argument is passed and when it isn't. I'm not sure if some kind of option string like --dir is the best way to go or what. And I'm wondering if I might be missing something really obvious solution, too.
Thanks.
I was able to cargo cult some little bash snippets and piece something that seems to do the trick and detect if last argument is a directory:
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
INITIAL_QUERY="${*:-}"
last="${#: -1}"
if [[ -d $last ]]; then
INITIAL_QUERY="${#:1:$#-1}";
dir=$last
echo $INITIAL_QUERY
fi
IFS=: read -ra selected < <(
FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY") $dir" \
fzf --ansi \
--color "hl:-1:underline,hl+:-1:underline:reverse" \
--disabled --query "$INITIAL_QUERY" \
--bind "change:reload:sleep 0.1; $RG_PREFIX {q} $dir || true" \
--bind "alt-enter:unbind(change,alt-enter)+change-prompt(2. fzf> )+enable-search+clear-query" \
--prompt '1. ripgrep> ' \
--delimiter : \
--preview "bat --color=always {1} --highlight-line {2}" \
--preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
)
[ -n "${selected[0]}" ] && nvim "${selected[0]}" "+${selected[1]}"
If you think there is a simpler way or a better, I'd love to hear.
I am tring to get the count for the records in a certain table in bash scripts but the $num is null when returned (should be a number). And the query is correct when I directly run in pgadmin that I can get the number of rows. Any one know what is wrong?
declare -a ROW=($(psql \
-X \
-U $DB_USER \
-h $DB_HOST \
-d $DB_NAME \
-p $DB_PORT \
--set ON_ERROR_STOP=on \
--no-align \
-t \
--field-separator ' ' \
--quiet \
-c "SELECT count(*) as num
FROM table_test)")
)
echo "num_error: $num here"
if [[ $num == 0 ]]; then
echo "no error occur within the past 1 hour"
elif [[ $num == '' ]]; then
echo "return nothing"
else echo "$num"
fi
SQL aliases don't become shell variables, so using AS num in the query will not set $num in the shell.
The output of the query is being put in the ROW array, so you can get the value you want from ${ROW[0]}. There's also no need to use an array if the query just returns a single value. So you could do:
num=$(psql \
-X \
-U $DB_USER \
-h $DB_HOST \
-d $DB_NAME \
-p $DB_PORT \
--set ON_ERROR_STOP=on \
--no-align \
-t \
--field-separator ' ' \
--quiet \
-c "SELECT count(*)
FROM table_test)")
)
This is my target, where i want to run a loop for each element in the list variable.
The problem is the loop runs but the test variable value is passed as empty
list = mlflow emr
common=$(someDir)/common
.PHONY:build
build:
for var in $(list); do \
cd ${common}; \
test=$(git diff --name-only --diff-filter=AM master | grep ^$(var)/); \
if [ "$(test)" != "" ]; then \
echo "condition met"; \
else \
echo "It is Not Setup"; \
fi \
done
Error:
bash-5.0# sudo make build n=1
for var in mlflow emr; do \
cd /mak/epa-toolchain/common; \
test=; \
if [ "" != "" ]; then \
echo "condition met"; \
else \
echo "It is Not Setup"; \
fi \
done
It is Not Setup
It is Not Setup
The $ is a special character to make: it introduces a make variable reference. So this:
$(git diff --name-only --diff-filter=AM master | grep ^$(var)/)
is not a shell $(...) command, it's a make variable with a very strange name. Wherever you want the shell to see $ you have to escape it as $$:
$$(git diff --name-only --diff-filter=AM master | grep ^$$var/)
(note you have to change $(var) to $$var because the former is a reference to a make variable var, but you are looping in the shell which sets the shell variable var).
Ditto this:
if [ "$(test)" != "" ]; then \
has to be:
if [ "$$test" != "" ]; then \
because test is a shell variable you just assigned, not a make variable.
I'm trying to set up a conditional --sort option in mongoexport but I'm having trouble with the string interpretation of my variable.
Here is the code I'm trying to run :
#!/bin/bash
if [[ $IS_PROD == "true" ]]
then
SORT='--sort "{_id : -1}"'
else
SORT=""
fi
$MONGODB_HOME/bin/mongoexport \
--host=$HOST \
--port=$PORT \
--username=$USER \
--password=$PWD \
--db=$DB \
--limit=$LIMIT \
$SORT \
--collection=my_collection | \
sed 's,\\,\\\\,g' \
> $TMP_FILE
While running this I get the following error error parsing command line options: invalid argument for flag '--sort' (expected string): invalid syntax
I've tried several quotes configuration and still couldn't make it work. Could someone please help me on this one?
Thanks
using bash array
#!/bin/bash
if [[ $IS_PROD == "true" ]]
then
SORT=(--sort "{_id : -1}")
else
SORT=()
fi
$MONGODB_HOME/bin/mongoexport \
--host=$HOST \
--port=$PORT \
--username=$USER \
--password=$PWD \
--db=$DB \
--limit=$LIMIT \
"${SORT[#]}" \
--collection=my_collection | \
sed 's,\\,\\\\,g' \
> $TMP_FILE
Explanation: using single quotes prevent shell expansions and double quotes are literal, but after variable expansion the double quotes are still litteral and expanded string is split by spaces.
Otherwise to work around unbound variable bug
#!/bin/bash
options=(--host=$HOST \
--port=$PORT \
--username=$USER \
--password=$PWD \
--db=$DB \
--limit=$LIMIT)
if [[ $IS_PROD == "true" ]]
then
options+=(--sort "{_id : -1}")
fi
$MONGODB_HOME/bin/mongoexport \
"${options[#]}" \
--collection=my_collection | \
sed 's,\\,\\\\,g' \
> $TMP_FILE
I have the following make file, which i think is a shell script.
I am trying to loop through FILE_DIR to perform some operations. However, i feel that the implementation isn't working as expected. So i am trying to insert some echo breakpoints.
Source:
# Target to recurse through the DIR_LIST and make each makefile found in that DIRS
ALLDIRS:
for se in $(FILE_DIR); do \
if [ -d $se ]; then \
cd $se; \
$(MAKE) -f Makefile.mk all; \
cd ..; \
fi \
done
Running:
$ make -f Makefile.batch
h: syntax error at line 3: `then' unexpected
*** Error code 2
The following command caused the error:
for se in `ls -p /app/internal|grep "/"`; do \
echo "Test" \
if [ -d e ]; then \
cd e; \
/usr/ccs/bin/make -f Makefile.mk all; \
cd ..; \
fi \
done
make: Fatal error: Command failed for target `ALLDIRS'
Can i please get help on this. Would like to insert an echo breakpoint.
One common error in Makefiles is using spaces instead of tabs in a command line. Check the whole for loop and make sure there are only tabs at the beginning of each line
ALLDIRS:
<tab>for se in $(FILE_DIR); do \
<tab><tab>if [ -d $se ]; then \
<tab><tab>cd $se; \
<tab><tab>$(MAKE) -f Makefile.mk all; \
<tab><tab>cd ..; \
<tab><tab>fi \
<tab>done
Another error is the dollar sign $. If you want a dollar sign in the shell command, you must double it in your commands, because otherwise dollar introduces a make variable and will be expanded before the shell sees it.
for se in $(FILE_DIR); do \
if [ -d $$se ]; then \
cd $$se; \
$(MAKE) -f Makefile.mk all; \
cd ..; \
fi \
done
And the final one, echo Test needs a semicolon as well
for se in $(FILE_DIR); do \
if [ -d $$se ]; then \
echo "Test"; \
cd $$se; \
...