why in Cygwin Terminal - the if statement work
and ubuntu - unix - not working for
this code :
#!/bin/sh
valid_password="pass"
echo "Please enter the password:"
read password
if [ "$password" == "$valid_password" ]
then
echo "You have access!"
else
echo "Access denied!"
fi
#emil pointed the answer:
if [ "$password" = "$valid_password" ]
instead of
if [ "$password" == "$valid_password" ]
Also: did you give the script executing permissions? Try
chmod +x script_name
because the correct syntax to [ is:
[ a = b ]
From your error message it sounds like you wrote:
if ["$password" = "$valid_password" ]
change this to:
if [ "$password" = "$valid_password" ]
notice the space after [. if just takes a shell command, try to run it and depending if the exit code from the program is 0 it will run the commands inside the if statement.
In your terminal, write i.e.:
user#localhost$ true; echo $?
0
to test your if statement:
user#localhost$ pass=pass; valid=pass
user#localhost$ if [ "$pass" = "$valid" ]; then echo 'You have access!'; fi
As #nullrevolution said, the ! is evaluated if you use double quotes, it will try to run last command in your shell history, in this case that is matching u.
user#localhost$ uname
Linux
user#localhost$ !u
uname
Linux
user#localhost$ echo "!"
sh: !: event not found
This is because the ! is evaluated before the double quotes are matched, and echo is run. If you still want to use double quotes, you will have to escape the ! outside the quotes:
echo "Access denied"\!
#nullrevolution also said you could try with bash, which has a builtin syntax for the expression inside if statements.
#!/bin/bash
valid_password=pass
echo "Please enter the password:"
read password
if [[ "$password" == "$valid_password" ]]; then
echo 'You have access!'
else
echo 'Access denied!'
fi
Also in your program I guess you do not want to echo the password in the terminal, to turn off echo temporary change:
read password
to
stty -echo
read password
stty echo
if you forgot to write stty echo to turn on echo again, just write reset in your terminal, and it will reset the terminal to default settings.
A useful tutorial for bourn shell script can be found here:
http://www.grymoire.com/Unix/Sh.html
Related
I'm wrote a function called test_status that I am trying to incorporate in my tmux status bar. To give some background, my tests will output to a file called .guard_result with either success or failure and the test_status function reads from that file and echoes a 💚 if my tests are passing and a ❤️ if they are failing.
The good news is running test_status works just fine, I'm just having trouble getting it to work with tmux. What am I missing here?
# ~/.oh-my-zsh/custom/aliases.zsh
function test_status {
if [ ! -f "./.guard_result" ]; then
echo "?"
return 1
fi
result="$(cat ./.guard_result)"
if [[ $result == *"success"* ]]
then
echo "💚";
elif [[ $result == *"fail"* ]]
then
echo "❤️";
fi
}
This function works... Here is Tmux configuration (which doesn't show result):
# ~/.tmux.conf
set -g status-right "#(test_status) #[fg=colour245]%d %b %Y #[fg=white]:: #[fg=colour245]%l:%M %p"
I know I must be missing something simple... Thanks for your help!
tmux passes shell commands to /bin/sh not zsh. And even if tmux would use zsh, the function would not be available in that context as ~/.zshrc, which loads oh-my-zsh, is only read for interactive shells.
In order to get the the output of test_status into tmux, I would suggest to put the function into a zsh script and call that.
You can either source ~/.oh-my-zsh/custom/aliases.zsh from within the script and then call test_status:
#!/usr/bin/zsh
# ^ make sure this reflects the path to zsh (`type zsh`)
source ~/.oh-my-zsh/custom/aliases.zsh
test_status
Or you can just put the entire function into the script, so as to not clutter alias.zsh:
#!/usr/bin/zsh
function test_status {
if [ ! -f "./.guard_result" ]; then
echo "?"
return 1
fi
result="$(cat ./.guard_result)"
if [[ $result == *"success"* ]]
then
echo "💚";
elif [[ $result == *"fail"* ]]
then
echo "❤️";
fi
}
Safe the script somewhere (e.g. /path/to/test_status.zsh), make it executable (chmod a+x /path/to/test_status.zsh) and call it by path in the tmux configuration.
I am writing a script where I need to list files without displaying them. The below script list the files while executing which I don't want to do. Just want to check if there are files in directory then execute "executing case 2".
ls -lrt /a/b/c/
if [ $? != 0 ]
then
echo "executing case 2"
else
echo "date +%D' '%TNo files found to process" >> $LOG
Testing the return code of ls won't do you a lot of good, because it'll return zero in both cases where it could list the directory.
You could do so with grep though.
e.g.:
ls | grep .
echo $?
This will be 'true' if grep matched anything (files were present). And false if not.
So in your example:
ls | grep .
if [ $? -eq 0 ]
then
echo "Directory has contents"
else
echo "directory is empty"
fi
Although be cautious with doing this sort of thing - it looks like you're in danger of a busy-wait test, which can make sysadmins unhappy.
If you don't need to see the output of ls, you could just make it a condition:
[ "$(ls -lrt a/b/c)" ] && echo "Not Empty" || echo "Empty"
Or better yet
[ "$(ls -A a/b/c)" ] && echo "Not Empty" || echo "Empty"
Since you don't care about long output (l) or display order (rt).
In a script, you could use this in an if statement:
#!/bin/sh
if [ "$(ls -A a/b/c)" ]; then
echo "Not empty"
else
echo "Empty"
fi
I just started writing shell scripts in Unix so, I am a total newbie
I want to read the arguments given when the user run the script
ex:
sh script -a abc
I want to read for argument -a user gave abc.
My code so far:
if ( $1 = "-a" )
then var=$2
fi
echo $var
I get an error.
Bash uses an external program called test to perform boolean tests, but that program is used mostly via its alias [.
if ( $1 = "-a" )
should become
if [ $1 = "-a" ]
if you use [ or
if test $1 = "-a"
#!/bin/sh
if [ $1 = "-a" ]; then
var=$2
fi
echo $var
You shoud be careful of the space between if and [
How to write a shell script named "backup.sh" which accepts one parameter, which would be a filename/directory.
Create a backup copy of that with the .bak appended to its name.Show message on success.
If the file/directory does not exist, show a proper message.
i did up to this point.please help me to figure this out
#!/bin/sh
#create_backup.sh
And add a .bak
bak="${backup.sh}.bak"
if [ "$#" -eq 0 ]
then
exit 1;
echo "File Succesfully backuped"
fi
cp ${1} "${1}.back"
echo "File is not found "
exit 0
#!/bin/bash -e
directory=$1
cp -r $directory $directory.bak
echo "Success"
obvious caveats with pathing/error codes/etc
I want to be able to tell if a command exists on any POSIX system from a shell script.
On Linux, I can do the following:
if which <command>; then
...snip...
fi
However, Solaris and MacOS which do not give an exit failure code when the command does not exist, they just print an error message to STDOUT.
Also, I recently discovered that the which command itself is not POSIX (see http://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html)
Any ideas?
command -v is a POSIX specified command that does what which does.
It is defined to to return >0 when the command is not found or an error occurs.
You could read the stdout/stderr of "which" into a variable or an array (using backticks) rather than checking for an exit code.
If the system does not have a "which" or "where" command, you could also grab the contents of the $PATH variable, then loop over all the directories and search for the given executable. That's essentially what which does (although it might use some caching/optimization of $PATH results).
One which utility is available as shell script in the Git repository of debianutils package of Debian Linux. The script seems to be POSIX compatible and you could use it, if you take into account copyright and license. Note that there have been some controversy whether or not and how the which utility should be deprecated; (at time of writing) current version in Git shows deprecation message whereas an earlier version added later removed -s option to enable silent operation.
command -v as such is problematic as it may output a shell function name, an alias definition, a keyword, a builtin or a non-executable file path. On the other hand some path(s) output by which would not be executed by shell if you run the respective argument as such or as an argument for command. As an alternative for using the which script, a POSIX shell function using command -v could be something like
#!/bin/sh
# Argument $1 should be the basename of the command to be searched for.
# Outputs the absolute path of the command with that name found first in
# a directory listed in PATH environment variable, if the name is not
# shadowed by a special built-in utility, a regular built-in utility not
# associated with a PATH search, or a shell reserved word; otherwise
# outputs nothing and returns 1. If this function prints something for
# an argument, it is the path of the same executable as what 'command'
# would execute for the same argument.
executable() {
if cmd=$(unset -f -- "$1"; command -v -- "$1") \
&& [ -z "${cmd##/*}" ] && [ -x "$cmd" ]; then
printf '%s\n' "$cmd"
else
return 1
fi
}
Disclaimer: Note that the script using command -v above does not find an executable whose name equals a name of a special built-in utility, a regular built-in utility not associated with a PATH search, or a shell reserved word. It might not find an executable either in case if there is non-executable file and executable file available in PATH search.
A function_command_exists for checking if a command exists:
#!/bin/sh
set -eu
function_command_exists() {
local command="$1"
local IFS=":" # paths are delimited with a colon in $PATH
# iterate over dir paths having executables
for search_dir in $PATH
do
# seek only in dir (excluding subdirs) for a file with an exact (case sensitive) name
found_path="$(find "$search_dir" -maxdepth 1 -name "$command" -type f 2>/dev/null)"
# (positive) if a path to a command was found and it was executable
test -n "$found_path" && \
test -x "$found_path" && \
return 0
done
# (negative) if a path to an executable of a command was not found
return 1
}
# example usage
echo "example 1";
command="ls"
if function_command_exists "$command"; then
echo "Command: "\'$command\'" exists"
else
echo "Command: "\'$command\'" does not exist"
fi
command="notpresent"
if function_command_exists "$command"; then
echo "Command: "\'$command\'" exists"
else
echo "Command: "\'$command\'" does not exist"
fi
echo "example 2";
command="ls"
function_command_exists "$command" && echo "Command: "\'$command\'" exists"
command="notpresent"
function_command_exists "$command" && echo "Command: "\'$command\'" does not exist"
echo "End of the script"
output:
example 1
Command: 'ls' exists
Command: 'notpresent' does not exist
example 2
Command: 'ls' exists
End of the script
Note that even the set -eu that turns -e option for the script was used the script was executed to the last line "End of the script"
There is no Command: 'notpresent' does not exist in the example 2 because of the && operator so the execution of echo "Command: "\'$command\'" does not exist" is skipped but the execution of the script continues till the end.
Note that the function_command_exists does not check if you have a right to execute the command. This needs to be done separately.
Solution with command -v <command-to-check>
#!/bin/sh
set -eu;
# check if a command exists (Yes)
command -v echo > /dev/null && status="$?" || status="$?"
if [ "${status}" = 127 ]; then
echo "<handle not found 1>"
fi
# check if a command exists (No)
command -v command-that-does-not-exists > /dev/null && status="$?" || status="$?"
if [ "${status}" = 127 ]; then
echo "<handle not found 2>"
fi
produces:
<handle not found 2>
because echo was found at the first example.
Solution with running a command and handling errors including command not found.
#!/bin/sh
set -eu;
# check if a command exists (No)
command -v command-that-does-not-exist > /dev/null && status="$?" || status="$?"
if [ "${status}" = 127 ]; then
echo "<handle not found 2>"
fi
# run command and handle errors (no problem expected, echo exist)
echo "three" && status="$?" || status="$?"
if [ "${status}" = 127 ]; then
echo "<handle not found 3>"
elif [ "${status}" -ne 0 ]; then
echo "<handle other error 3>"
fi
# run command and handle errors (<handle not found 4> expected)
command-that-does-not-exist && status="$?" || status="$?"
if [ "${status}" = 127 ]; then
echo "<handle not found 4>"
elif [ "${status}" -ne 0 ]; then
echo "<handle other error 4>"
fi
# run command and handle errors (command exists but <handle other error 5> expected)
ls non-existing-path && status="$?" || status="$?"
if [ "${status}" = 127 ]; then
echo "<handle not found 5>"
elif [ "${status}" -ne 0 ]; then
echo "<handle other error 5>"
fi
produces:
<handle not found 2>
three
./function_command_exists.sh: 34: ./function_command_exists.sh: command-that-does-not-exist: not found
<handle not found 4>
ls: cannot access 'non-existing-path': No such file or directory
<handle other error 5>
The following works in both bash and zsh and avoids both functions and aliases.
It returns 1 if the binary is not found.
bin_path () {
if [[ -n ${ZSH_VERSION:-} ]]; then
builtin whence -cp "$1" 2> /dev/null
else
builtin type -P "$1"
fi
}