I've copied a script from the unifi documentation
#!/bin/sh
## define required variables
username=admin
password=admin
baseurl=https://localhost:8443
## include the API library
. unifi_sh_api
unifi_login
# unifi_authorize_guest <mac> <minutes> [up=kbps] [down=kbps] [bytes=MB]
unifi_authorize_guest $1 $2
unifi_logout
This is the script and this is the file structure:
foo#site:/home/foo# ls
unifi.sh unifi_sh_api
This is what I get when I try to execute the file. What can cause this? The file is obviously in the right folder.
foo#site:/home/foo# sh unifi.sh
unifi.sh: 9: .: unifi_sh_api: not found
You are invoking bash as /bin/sh which puts bash into sh-compatibility mode. The POSIX standard says that:
If file does not contain a slash, the shell shall use the search path specified by PATH to find the directory containing file.
Which means that the current directory will not be searched unless it is part of $PATH:
$ /bin/sh -c '. test.sh'
/bin/sh: 1: .: t.sh: not found
$ /bin/sh -c 'PATH=".:$PATH"; . test.sh'
$
bash, however, seems to search the current directory:
$ /bin/bash -c '. test.sh'
$
Related
$ bl 1
$ sh -c 'bl 1'
sh: bl: command not found
The bl script is located in the user's PATH extension (/home/user/.local/bin) but the sh environment does not seem to be aware of it, the bash is. The main /usr/bin/sh executable symlinks to /usr/bin/bash.
Placing a symlink in /usr/local/bin pointing to the local bl script does seem to fix the issue. Expanding the PATH manually $ PATH=/usr/bin:$HOME/.local/bin sh -c 'bl 1' also solves it, something I don't really understand since both the bash and the sh are aware of the PATH.
$ export -p |grep PATH=
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/bin:~/.local/bin"
$ sh -c 'export -p |grep PATH'
export PATH="/usr/local/sbin:/usr/local/bin:/usr/bin:~/.local/bin"
"Something's missing and you have to find it" yet it's hard to look if you don't know what is missing.
$ export -p |grep PATH
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/bin:~/.local/bin"
Having a literal ~ is wrong. It should have been expanded to /home/user already. The shell will expand ~ when variables are assigned but not when they're expanded.
$ foo=~ && echo $foo # expanded at assignment
/home/user
$ foo='~' && echo $foo # not expanded since the assignment is quoted
~
Find the shell startup script where ~/.local/bin is added to the $PATH and make sure ~ is not quoted.
Wrong:
PATH="$PATH:~/.local/bin"
Right:
PATH=$PATH:~/.local/bin
this is part of my current code
#! /bin/bash
#Take no arguments in
#checks to see if home/deleted is in existence
#creates the directory or file if it is missing
**(line 15)** function checkbin(){
if [ ! -c "~/deleted" ]; then
mkdir -p ~/deleted
fi
if [ ! -f "~/.restore.info" ]; then
touch ~/deleted/.restore.info
fi
}
I can call this code properly using ./remove [ARGS]
however when I call using sh remove [ARGS]
I receive the following error remove: 15: remove: Syntax error: "(" unexpected
ls -l on the file -rwxr-x--x
Does unix support execution on both sh and ./ ?
when executing with ./ /bin/bash is used (as define in shebang) whereas sh may be another interpreter or a link to bash which can have a different behaviour depending on how it is called sh.
bash is derived from sh but has some specific syntax:
for example in sh Function Definition Command is
fname() compound-command[io-redirect ...]
without function keyword.
For more details
Bash
Posix shell
If you want your script to run in sh as well as in bash, you need to be writing to the POSIX shell standard.
In this case, that means not using the Bash function keyword:
checkbin(){
test -c "~/deleted" || mkdir -p ~/deleted
test -f "~/.restore.info" || touch ~/deleted/.restore.info
}
If you're writing portable shell, then it's a good idea to use #!/bin/sh as your shebang.
(BTW, I assume you're aware that "~/deleted" and ~/deleted are in no way alike?)
I have the following script:
#!/bin/bash
set -o errexit # Exit on error
# Enable script to run from anywhere
root="$(dirname ${BASH_SOURCE[0]})"
cd "$($root)"
source ./scripts/main
cd "$($root)"
pwd
source ./scripts/test
cd "$($root)/applicant"
yarn build
But I get this error:
./build.sh: line 8: .: filename argument required
How can I get a variable of the current directory?
you can use pwd for current directory.
-61T9:~ pwd
/Users/test
-61T9:~ s=`pwd`
-61T9:~ echo $s
/Users/test
You can do it simply:
cd $variable_with_path
In your example you should replace "$($root)" by $root
To get variable with current directory:
path=`pwd`
When I enter this command:
./vw -d click.train.vw -f click.model.vw --loss_function logistic
on cygwin I got this error:
-bash: ./vw: No such file or directory
I actually want to implement "PREDICTING CTR WITH ONLINE MACHINE LEARNING" website link for reference :
http://mlwave.com/predicting-click-through-rates-with-online-machine-learning/
Any help would be appreciated.
Answer based on common mistakes.
Execution by inexact name
Filename with blanks
Suppose you write ls in the command line and obtain the following:
$ ls
anyfile command
Then, you call your command with ./command and get the following:
$ ./command
bash: ./command: No such file or directory
Here you can think ls is wrong, but the actuality is that you can't easily recognize if a filename have, for example, leading or trailing spaces:
$ ls -Q # -Q, --quote-name -> enclose entry names in double quotes
"anyfile" "command "
As you see, here my command has a trailing space:
$ ./"command " # it works
Filename with extension
A common mistake is to call the command by the name without the extension (if any).
Let's name the command: command.sh:
$ ./command # wrong
$ ./command.sh # OK
Wrong file path
If you call your command with the prefix ./, it needs to be in your current directory ($PWD). If it is not, you will get:
$ ./command # relative path -> same as "$PWD/command"
bash: ./command: No such file or directory
In that case, you can try the following:
Executing the command by its absolute path
$ /home/user/command # absolute path (example). It starts with a slash (/).
Let the shell locate the command
If you provide just the command name without slashes, bash searches in each directory of the $PATH variable, for an executable file named command.
$ command
You can do that search with the which command:
$ which command
/usr/bin/command
If the search fails, you'll get comething like:
$ which unexistent_command
which: no unexistent_command in (/usr/local/sbin:/usr/local/bin:/usr/bin)
Broken link
Now, suppose you write ls -Q in the command line and obtain the following:
$ ls -Q
"anyfile" "command"
This time, you can be 100% secure command exists but when you try to execute it:
$ ./command
bash: ./command: No such file or directory
Reason? bash complains command doesn't exist, but what doesn't exist is the file command is pointing to by a Symbolic link. e.g.:
$ ls -l
total 0
-rw-r--r-- 1 user users 0 Jan 14 02:12 anyfile
lrwxrwxrwx 1 user users 27 Jan 14 02:12 command -> /usr/bin/unexistent_command
$ ls /usr/bin/unexistent_command
ls: cannot access /usr/bin/unexistent_command: No such file or directory
Notice that the following surely throw different errors that the one you are getting...
Execution permission
To execute a file, it must have the x bit activated. With ls -l you can check the file permission.
$ ls -l command
-rw-r--r-- 1 user users 0 Jan 3 19:52 command
In this case (it doesn't have the x bit activated), you can give permission with chmod:
$ chmod +x command
$ ls -l command
-rwxr-xr-x 1 user users 0 Jan 3 19:52 command
I have the following simple bash script:
#!/bin/bash -fx
ls *sh
The problem is that bash add a quote to the pattern and I get wrong output.
+ ls '*sh'
ls: cannot access *sh: No such file or directory
How can I change this behavior?
The output of ls *sh from the terminal is:
$ls *sh
a.bash a.sh b.sh
I tried to add quotes according to this post - "Bash variable containing file wildcard"
without success
That because you're disabling pathname expansion with the -f option.
#!/bin/bash -fx
From man:
-f
Disable filename expansion (globbing).