Shell can't open libs/init another shell script - bash

I have a shell script, that should import another shell script:
#!/bin/sh
. libs/init
However it complains:
/sh/main.sh: 3: .: Can't open libs/init
the folder is structured as follows:
the content of the init.sh file:
#!/bin/sh
echo "<===========================================>"
echo "Check if all variables are set"
echo "<===========================================>"
[ -z "$DO_AC" ] && exit 1
[ -z "$K8S_CLUSTER" ] && exit 1
[ -z "$ARGO_SERVER" ] && exit 1
[ -z "$ARGO_USERNAME" ] && exit 1
[ -z "$ARGO_PW" ] && exit 1
[ -z "$IMAGE_URL" ] && exit 1
[ -z "$IMAGE_VERSION" ] && exit 1
[ -z "$CHARTS_URL" ] && exit 1
[ -z "$GITOPS_URL" ] && exit 1
[ -z "$APP_TYPE" ] && exit 1
[ -z "$APP" ] && exit 1
[ -z "$APP_URL" ] && exit 1
[ -z "$GIT_USER" ] && exit 1
[ -z "$GIT_AT" ] && exit 1
[ -z "$APP_TLS_SECRET" ] && exit 1
echo "All variables are set"
What am I doing wrong?

chmod u+r init.sh
That will make sure you've got read access to the file, which that error message suggested to me, might be your problem. Permissions sometimes get changed for screwy reasons; as long as you're not randomly setting things suid root, however, it's not too much of a disaster.

Related

Keep retrying yarn script until it passes

I am new to bash and wondering if there is a way to run a script x amount of times until it succeeds? I have the following script, but it naturally bails out and doesn't retry until it succeeds.
yarn graphql
if [ $? -eq 0 ]
then
echo "SUCCESS"
else
echo "FAIL"
fi
I can see there is a way to continuously loop, however is there a way to throttle this to say, loop every second, for 30 seconds?
while :
do
command
done
I guess you could devise a dedicated bash function for this, relying on the sleep command.
E.g., this code is freely inspired from that code by Travis, distributed under the MIT license:
#!/usr/bin/env bash
ANSI_GREEN="\033[32;1m"
ANSI_RED="\033[31;1m"
ANSI_RESET="\033[0m"
usage() {
cat >&2 <<EOF
Usage: retry_until WAIT MAX_TIMES COMMAND...
Examples:
retry_until 1s 3 echo ok
retry_until 1s 3 false
retry_until 1s 0 false
retry_until 30s 0 false
EOF
}
retry_until() {
[ $# -lt 3 ] && { usage; return 2; }
local wait_for="$1" # e.g., "30s"
local max_times="$2" # e.g., "3" (or "0" to have no limit)
shift 2
local result=0
local count=1
local str_of=''
[ "$max_times" -gt 0 ] && str_of=" of $max_times"
while [ "$count" -le "$max_times" ] || [ "$max_times" -le 0 ]; do
[ "$result" -ne 0 ] && {
echo -e "\n${ANSI_RED}The command '$*' failed. Retrying, #$count$str_of.${ANSI_RESET}\n" >&2
}
"$#" && {
echo -e "\n${ANSI_GREEN}The command '$*' succeeded on attempt #$count.${ANSI_RESET}\n" >&2
result=0
break
} || result=$?
count=$((count + 1))
sleep "$wait_for"
done
[ "$max_times" -gt 0 ] && [ "$count" -gt "$max_times" ] && {
echo -e "\n${ANSI_RED}The command '$*' failed $max_times times.${ANSI_RESET}\n" >&2
}
return "$result"
}
Then to fully answer your question, you could run:
retry_until 1s 30 command

How to write a script with multiple pings as condition to run a command?

I need to be sure that 2 machines are functional and 1 machine is sleeping to run my command. Here the logic:
#!/bin/bash
ping1=$(192.168.2.15)
ping2=$(192.168.2.15)
ping3=$(192.168.2.21)
if [ $ping1 = OK ] && [ $ping2 = OK ] && [ $ping3 = failure ]
then run_command
elif [ ping1 = OK ] && [ ping2 = OK ] && [ ping3 = OK ]
then echo 'machine 3 already running'
fi
I know the syntax is bad, because i don't know what do i have to write in the [ ]?
Shell commands have a return status accessible by $?, ping will return 0 if it was successful, and something else instead, so we might as well test on that.
We can retrieve the status this way :
ping -c 1 192.168.2.15; ping1=$?
ping -c 1 192.168.2.17; ping2=$?
ping -c 1 192.168.2.21; ping3=$?
where -c 1 will tell ping to only send one request.
Then we can test the values using numerical comparison :
if [ $ping1 -eq 0 ] && [ $ping2 -eq 0 ] && [ $ping3 -ne 0 ]
By the way, I would factor your tests into this form :
if ping1 && ping2 then
if ping3 then
else #(if ! ping3)
fi
fi

Chosing "input" in an AND (&&) and OR (||) list of commands

I have to find a way to have my script read from one of these three options:
a file argument
standard input
a previously established environment variable
Here's what I currently have:
#!/bin/bash
key=$1
[ $# -ge 1 -a -f "$2" ] && input="$2" || [ -f "$INPUT" ] && input="$INPUT" || input="-"
echo $input
Only the environment variable refuses to work, the rest works fine.
I've tried using the export INPUT="pathnametofile" before but it doesn't make any difference, I end up with the shell asking me to enter info as if I called on cat.
The problem in your script
Your attemp is not working due to the way the shell processes a Lists of Commands:
‘&&’ and ‘||’ have equal precedence.
AND and OR lists are executed with left associativity.
Your sentence:
[ $# -ge 1 -a -f "$2" ] && input="$2" || [ -f "$INPUT" ] && input="$INPUT" || input="-"
does the same as follows:
[ $# -ge 1 -a -f "$2" ] && input="$2"
[ $? -eq 0 ] || [ -f "$INPUT" ]
[ $? -eq 0 ] && input="$INPUT"
[ $? -eq 0 ] || input="-"
Now yo may see why your unexpected behaviour.
A better attempt grouping commands
{ [ $# -ge 1 -a -f "$2" ] && input="$2"; } || { [ -f "$INPUT" ] && input="$INPUT"; } || input="-"
Now, due to precedence, the first group is not needed at all:
[ $# -ge 1 -a -f "$2" ] && input="$2" || { [ -f "$INPUT" ] && input="$INPUT"; } || input="-"
Furthermore, unless you have set the positional parameters by hand, you can remove the first check (after all, if $2 is emtpy, -f "" fails the same).
[ -f "$2" ] && input="$2" || { [ -f "$INPUT" ] && input="$INPUT"; } || input="-"
An alternative with the if conditional construct
if [ -f "$2" ]; then
input=$2
elif [ -f "$INPUT" ]; then
input=$INPUT
fi
echo "${input:=-}"
untested, but you'll probably have better luck with if commands, and test that the variable is not empty:
if [ $# -ge 1 -a -f "$2" ]; then
input="$2"
elif [ -n "$INPUT" -a -f "$INPUT" ]; then
input="$INPUT"
else
input="-"
fi

Can I use simply exitcode within test expression (without $?)?

I have to make a conditional in ash, that depends on result of two commands. The problem is one of them returns the result to stdout, the other as exitcode.
Do I have to write
command2
RET=$?
if [ `command1` -eq 1 -a $RET -eq 2 ] ; then ...
or is there some construct that would let me simply access return code of command2 within logic of [ ] ?
if [ `command1` -eq 1 -a ${{{ command2 }}} -eq 2 ] ; then ...
( with ${{{ }}}} being the magical expression extracting the returncode ? )
It would be better to write:
if [ "`command1`" -eq 1 ] && command2
then
....
fi
Or when you want to check if the exit code is 2 then:
if [ "`command1`" -eq 1 ] && { command2 ; [ "$?" = 2 ] ; }
then
....
fi
Example:
$ cat 1.sh
ARG="$1"
command1()
{
echo 1
}
command2()
{
return "$ARG"
}
if [ "`command1`" -eq 1 ] && { command2 ; [ "$?" = 2 ] ; }
then
echo OK
else
echo FAILED
fi
$ sh 1.sh 2
OK
$ sh 1.sh 3
FAILED
I guess there is no way to avoid $?, but I can use the command inside test statement, by adding ;echo $? at the end.
if [ `command1` -eq 1 -a `command2 ; echo $?` -eq 2 ] ; then ...

Bash - Troubling result with IF [..] || [..]

I can seem to see why this doesn't work:
#!/bin/bash
if [ $# -ne 1 ] || [ $# -ne 2 ]; then
# Should run if there are either 1 or 2 options specified
echo "usage: ${0##*/} <username>"
exit
fi
When testing to see if it works:
root#ubuntu:~# testing.sh optionone optiontwo
...Correct output...
root#ubuntu:~# testing.sh optionone
usage: testing.sh <username>
Change the boolean logic:
if [ $# -ne 1 ] && [ $# -ne 2 ]; then
Or
if ! ( [ $# -eq 1 ] || [ $# -eq 2 ] ); then
BTW, you can use Shell-Arithmetic ((...)):
if (( $#!=1 && $#!=2 )); then
Note that you are executing 2 commands in:
[ $# -ne 1 ] || [ $# -ne 2 ]
[ $# -ne 1 ] is a 1st command, and the [ $# -ne 2 ] command is executed only if the previous has a non-zero error code as of the || shell operator.
In your case, it is not important, but in the case bellow, it is:
[ $? -eq 0 ] || [ $? -eq 1 ]
The 2nd command will always be true, as the 2nd $? is the return code of [ $? -eq 0 ]. You can test it with the lines bellow that will print true twice:
function f() { return $1; }
f 1
{ [ $? -eq 0 ] || [ $? -eq 1 ]; } && echo "true"
f 2
{ [ $? -eq 0 ] || [ $? -eq 1 ]; } && echo "true"
The correct way to execute a or in a single command is:
[ $? -eq 0 -o $? -eq 1 ]
This way, those bellow only print true once:
function f() { return $1; }
f 1
{ [ $? -eq 0 -o $? -eq 1 ]; } && echo "true"
f 2
{ [ $? -eq 0 -o $? -eq 1 ]; } && echo "true"
And concerning your original question, kev has already point out that there was a logic error in your test. The negative of [ $# -eq 1 ] || [ $# -eq 2 ] is NOT [ $# -eq 1 ] && NOT [ $# -eq 2 ] and this becomes [ $# -ne 1 ] && [ $# -ne 2 ] or in a single command:
[ $# -ne 1 -a $# -ne 2 ]
One way to make this work is to switch out the -ne comparison operator for -lt and -gt (less than and greater than) for the conditional statement. Like this:
#!/bin/bash
#Should run if there are either 1 or 2 options specified
if [ $# -lt 1 ] || [ $# -gt 2 ]; then
echo "usage: ${0##*/} <username>"
exit
fi

Resources