What is the fish equivalent to a bash if/then/else/fi block? - shell

I am using termux and it has no init system, i found a script to start crond when i start the app
if ! pgrep -f "crond" >/dev/null; then
echo "[Starting crond...]" && crond && echo "[OK]"
else
echo "[crond is running]"
fi
this code worked perfectly for bash shell.
I am currently using fish shell and tried using the same code in the fish equivalent of bash_profile AKA config.fish however, i got the error message
Missing end to balance this if statement
if ! pgrep -f "crond" >/dev/null; then
^
from sourcing file ~/.config/fish/config.fish
called during startup
Please help me with translations, I'm reading through fish docs however it will take me a long time to get it right.

Honestly, you haven't made any effort to learn anything about the fish shell. You should start with the tutorial. There you will learn that if blocks look like this:
if pgrep -f "crond" >/dev/null
do_something
end

This answer by glenn-jackman is very helpful https://stackoverflow.com/a/29671880/5257034
i am able to run the code in config.fish without issues
my code
if ! pgrep -f $crond >/dev/null
echo "[Starting crond...]"; and crond; and echo "[OK]"
else
echo "[crond is running]"
end

Related

nesting if in a for loop for aws cli commands [duplicate]

I am trying to compare strings in bash. I already found an answer on how to do it on stackoverflow. In script I am trying, I am using the code submitted by Adam in the mentioned question:
#!/bin/bash
string='My string';
if [[ "$string" == *My* ]]
then
echo "It's there!";
fi
needle='y s'
if [[ "$string" == *"$needle"* ]]; then
echo "haystack '$string' contains needle '$needle'"
fi
I also tried approach from ubuntuforums that you can find in 2nd post
if [[ $var =~ regexp ]]; then
#do something
fi
In both cases I receive error:
[[: not found
What am I doing wrong?
[[ is a bash-builtin. Your /bin/bash doesn't seem to be an actual bash.
From a comment:
Add #!/bin/bash at the top of file
How you are running your script?
If you did with
$ sh myscript
you should try:
$ bash myscript
or, if the script is executable:
$ ./myscript
sh and bash are two different shells. While in the first case you are passing your script as an argument to the sh interpreter, in the second case you decide on the very first line which interpreter will be used.
Is the first line in your script:
#!/bin/bash
or
#!/bin/sh
the sh shell produces this error messages, not bash
As #Ansgar mentioned, [[ is a bashism, ie built into Bash and not available for other shells. If you want your script to be portable, use [. Comparisons will also need a different syntax: change == to =.
if [ $MYVAR = "myvalue" ]; then
echo "true"
else
echo "false"
fi
I had this problem when installing Heroku Toolbelt
This is how I solved the problem
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 ago 15 2012 /bin/sh -> dash
As you can see, /bin/sh is a link to "dash" (not bash), and [[ is bash syntactic sugarness. So I just replaced the link to /bin/bash. Careful using rm like this in your system!
$ sudo rm /bin/sh
$ sudo ln -s /bin/bash /bin/sh
If you know you're on bash, and still get this error, make sure you write the if with spaces.
[[1==1]] # This outputs error
[[ 1==1 ]] # OK
Specify bash instead of sh when running the script. I personally noticed they are different under ubuntu 12.10:
bash script.sh arg0 ... argn
Execute in your terminal:
sudo update-alternatives --install /bin/sh sh /bin/bash 100
Make the file executable and then execute without sh.
make it executable by $ chmod +x filename
then instead of sh filename use ./filename

Reliable way to require only bash shell in script

I wonder if there are any reliable methods (cross-shell compatible) to require bash as shell interpreter for my script.
For example, I have shell script that can be run only with bash interpreter. Despite of #!/usr/bin/bash at the beginning of my script some smart user/hacker can run it directly with another shell: $ csh script.sh
This can lead to unwanted consequences.
I already thought about testing echo $0 output and exiting with error code but syntax for if statements (as long as for another conditional statements) is different among various shell interpreters. Testing directly for $BASH_VERSION variable is unreliable due to the same limitations.
Are there any cross-shell compatible and reliable way to determine current interpreter?
Thank you!
EDIT: as for now I have the following basic check for compatibility:
### error codes
E_NOTABASH=1
E_OLD_BASH=2
# perform some checks
if [ -z "$BASH_VERSION" ]
then
echo -e "ERROR: this script support only BASH interpreter! Exiting" >&2
exit $E_NOTABASH
fi
if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]
then
echo -e "ERROR: this script needs BASH 4.0 or greater! Your current version is $BASH_VERSION. Exiting" >&2
exit $E_OLD_BASH
fi
Not entirely sure I understand the scope of the question.
A #! /usr/bin/env bash shebang will fail if there's no bash, but to keep it from being explicitly parsed by another shell, um...
How about -
case "$BASH_VERSION" in
4.*) : bash version 4+ so ok ;;
*) echo "please run only with bash v4+. Aborting."
exit 1 ;;
esac
If the syntax works, it is either right or hacked.
If it crashes, you're good. :)
you could check for the parent process id, command respectively
pstree -p $$ | grep -m 1 -oE '^[^\(]+'
or
ps $(ps -o ppid=$$)

How to check the current shell and change it to bash via script?

#!/bin/bash
if [ ! -f readexportfile ]; then
echo "readexportfile does not exist"
exit 0
fi
The above is part of my script. When the current shell is /bin/csh my script fails with the following error:
If: Expression Syntax
Then: Command not found
If I run bash and then run my script, it runs fine(as expected).
So the question is: If there is any way that myscript can change the current shell and then interpretate rest of the code.
PS: If i keep bash in my script, it changes the current shell and rest of the code in script doesn't get executed.
The other replies are correct, however, to answer your question, this should do the trick:
[[ $(basename $SHELL) = 'bash' ]] || exec /bin/bash
The exec builtin replaces the current shell with the given command (in this case, /bin/bash).
You can use SHEBANG(#!) to overcome your issue.
In your code you are already using she-bang but make sure it is first and foremost line.
$ cat test.sh
#!/bin/bash
if [ ! -f readexportfile ]; then
echo "readexportfile does not exist"
exit 0
else
echo "No File"
fi
$ ./test.sh
readexportfile does not exist
$ echo $SHELL
/bin/tcsh
In the above code even though I am using CSH that code executed as we mentioned shebang in the code. In case if there is no shebang then it will take the help of shell in which you are already logged in.
In you case you also check the location of bash interpreter using
$ which bash
or
$ cat /etc/shells |grep bash

shell script comparing two variables

I have created a script for updating some ipaddress in iptables. Hereby I'm describing the issues which I'm facing with that.
Issues:
Comparison not happening between two variables within a script
At the end of script i need to execute a command ie; service restart/stop etc and output of the commands should be visible while executing the script.
1) Here am comparing two variable strings:
BASE=172.31.0.0
CMD=172.31.1.0
if [[ "$CMD" == "$BASE" ]]; then
echo "ip are same"
else
echo "not matched"
fi
but there is no response/output while executing the above script. Here its not comparison is not happening..Kindly suggest a best solution to resolve this issue.
2) after executing the script I need to restart the iptables:
BASE=172.31.0.0
CMD=172.31.1.0
if [[ "$CMD" == "$BASE" ]]; then
echo "ip are same"
else
echo "not matched"
fi
service iptables restart
iptables -nvL
A script should display the output of the last two lines (commands). Kindly suggest me the best solution and how to do this in a best way.
That's very odd. This should work, so if it's not working you forgot to mention something important.
How is this script being executed? Do you simply type ./script or is it executed by some service (like cron)?
Here are some of suggestions to debug:
Sanity check: see if bash works (perhaps your login shell isn't bash, so you didn't notice). Run this at the terminal:
/bin/bash -c 'echo hello world'
It prints hello world, right? How about this:
/bin/bash -c 'BASE=172.31.0.0; CMD=172.31.1.0; if [[ "$CMD" == "$BASE" ]]; then echo "ip are same"; else echo "not matched"; fi'
If any of the above doesn't work, you have a problem with your bash installation.
Instead of executing your script with ./script.sh, run it like this:
/bin/bash script.sh
Nothing? Run this:
file script.sh
If it ends with something like "with CRLF line terminators", then cdarke nailed it: the file was created on Windows with an improper tool. Recreate it on Linux or use dos2unix. But anyway, I doubt it because with a CRLF-ending file I get this printed:
bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
Instead of nothing at all.
Put those this line on the beginning of the file:
set -x
(below #!/bin/bash, if you have it). This ensures a debugging trace will be printed, showing each command as it is executed.
If still there is nothing shown.. put this at your script (below set -x if you put it):
touch /tmp/hi-this-is-strange
Then check if there is a /tmp/hi-this-is-strange file after you run the script.

Getting exit code of last shell command in another script

I am trying to beef up my notify script. The way the script works is that I put it behind a long running shell command and then all sorts of notifications get invoked after the long running script finished.
For example:
sleep 100; my_notify
It would be nice to get the exit code of the long running script. The problem is that calling my_notify creates a new process that does not have access to the $? variable.
Compare:
~ $: ls nonexisting_file; echo "exit code: $?"; echo "PPID: $PPID"
ls: nonexisting_file: No such file or directory
exit code: 1
PPID: 6203
vs.
~ $: ls nonexisting_file; my_notify
ls: nonexisting_file: No such file or directory
exit code: 0
PPID: 6205
The my_notify script has the following in it:
#!/bin/sh
echo "exit code: $?"
echo "PPID: $PPID"
I am looking for a way to get the exit code of the previous command without changing the structure of the command too much. I am aware of the fact that if I change it to work more like time, e.g. my_notify longrunning_command... my problem would be solved, but I actually like that I can tack it at the end of a command and I fear complications of this second solution.
Can this be done or is it fundamentally incompatible with the way that shells work?
My shell is Z shell (zsh), but I would like it to work with Bash as well.
You'd really need to use a shell function in order to accomplish that. For a simple script like that it should be pretty easy to have it working in both zsh and bash. Just place the following in a file:
my_notify() {
echo "exit code: $?"
echo "PPID: $PPID"
}
Then source that file from your shell startup files. Although since that would be run from within your interactive shell, you may want to use $$ rather than $PPID.
It is incompatible. $? only exists within the current shell; if you want it available in subprocesses then you must copy it to an environment variable.
The alternative is to write a shell function that uses it in some way instead.
One method to implement this could be to use EOF tag and a master script which will create your my_notify script.
#!/bin/bash
if [ -f my_notify ] ; then
rm -rf my_notify
fi
if [ -f my_temp ] ; then
rm -rf my_temp
fi
retval=`ls non_existent_file &> /dev/null ; echo $?`
ppid=$PPID
echo "retval=$retval"
echo "ppid=$ppid"
cat >> my_notify << 'EOF'
#!/bin/bash
echo "exit code: $retval"
echo " PPID =$ppid"
EOF
sh my_notify
You can refine this script for your purpose.

Resources