Hello, this maybe a bit of a silly question, but how do you run a script from a another directory for example in this directories:
~/dir1/dir2/dir3/script.sh
I've tried ./script.sh but doesnt seem to work, also what is the best way to determine how to run a script if you are not sure?
The leading dot in your command means "relative to the current directory". Remove it and it'll refer to "the file someScript in the directory /home/user/scripts:
/home/user/scripts/someScript
If you get "Permission denied", it's either because you do not have sufficient permissions to access the file in the directory of other users or because the file is not executable. To make it executable, run:
chmod +x /home/user/scripts/someScript
If your script needs to access resources in the same folder that it is being run from, and you have it specified as relative paths, then your script will break.
I always add a cd $(dirname $0) to the head of my script so the folder containing the script will be the root folder.
shell - How can Bash execute a command in a different directory context? - Stack Overflow
linux - Execute a specific command in a given directory without cd'ing to it? - Unix & Linux Stack Exchange
how to execute a shell script from any directory - Unix & Linux Stack Exchange
linux - Execute bash script from one into another directory? - Stack Overflow
Videos
sh /path/to/script will spawn a new shell and run she script independent of your current shell. The source (.) command will call all the commands in the script in the current shell. If the script happens to call exit for example, then you'll lose the current shell. Because of this it is usually safer to call scripts in a separate shell with sh or to execute them as binaries using either the full (starting with /) or relative path (./). If called as binaries, they will be executed with the specified interpreter (#!/bin/bash, for example).
As for knowing whether or not a script will find the files it needs, there is no good answer, other than looking at the script to see what it does. As an option, you could always go to the script's folder in a sub-process without leaving your current folder:
(cd /wherever/ ; sh script.sh)
You can definitely do that (with the adjustments the others mentioned like sudo sh /pathto/script.sh or ./script.sh). However, I do one of a few things to run them system wide to not worry about dirs and save me useless extra typing.
1) Symlink to /usr/bin
ln -s /home/username/Scripts/name.sh /usr/bin/name
(be sure there is no overlapping name there, because you would obviously override it.) This also lets me keep them in my development folders so I can adjust as necessary.
2) Add the Scripts dir to your path (using .bash_profile - or whatever.profile you have on your shell)
PATH=/path/to/scripts/:$PATH
3) Create Alias's in the .bash_profile in ~/.bash_profile add something like:
alias l="ls -l"
As you can tell, the syntax is just alias, digits you want to act as a command, the command. So typing "l" anywhere in the terminal would result in ls -l If you want sudo, just alias sl="sudo ls -l" to note to yourself l vs sl (as a useless example).
Either way, you can just type sudo nameofscript and be on your way. No need to mess with ./ or . or sh, etc. Just mark them as executable first :D
Use cd in a subshell; the shorthand way to use this kind of subshell is parentheses.
(cd wherever; mycommand ...)
That said, if your command has an environment that it requires, it should really ensure that environment itself instead of putting the onus on anything that might want to use it (unless it's an internal command used in very specific circumstances in the context of a well defined larger system, such that any caller already needs to ensure the environment it requires). Usually this would be some kind of shell script wrapper.
(cd /path/to/your/special/place;/bin/your-special-command ARGS)
I don't know if this counts, but you can make a subshell:
$ (cd /var/log && cp -- *.log ~/Desktop)
The directory is only changed for that subshell, so you avoid the work of needing to cd - afterwards.
Not to undermine the value of answers given by other people, but I believe what you want is this:
(cd /path/to && ./executable [ARGS])
Note the parens to invoke cd in a sub-shell.
I understand from your comments that you want your script to have its current working directory to be in A/B/C when it executes. Ok, so you go into directory A:
cd A
and then execute script.sh from there:
(cd B/C; ./script.sh)
What this does is start a subshell in which you first change to the directory you want your script to execute in and then executes the script. Putting it as a subshell prevents it from messing up the current directory of your interactive session.
If it is a long running script that you want to keep in the background you can also just add & at the end like any other command.
Whenever I want to make sure that a script can access files in its local folder, I throw this in near the top of the script:
# Ensure working directory is local to this script
cd "$(dirname "$0")"
It sounds like this is exactly what you're looking for!
Call the program like this:
(cd /c; /a/helloworld)
The parentheses cause a sub-shell to be spawned. This sub-shell then changes its working directory to /c, then executes helloworld from /a. After the program exits, the sub-shell terminates, returning you to your prompt of the parent shell, in the directory you started from.
Error handling: To avoid running the program without having changed the directory, e.g. when having misspelled /c, make the execution of helloworld conditional:
(cd /c && /a/helloworld)
Reducing memory usage: To avoid having the subshell waste memory while hello world executes, call helloworld via exec:
(cd /c && exec /a/helloworld)
[Thanks to Josh and Juliano for giving tips on improving this answer!]
Similar to David Schmitt's answer, plus Josh's suggestion, but doesn't leave a shell process running:
(cd /c && exec /a/helloworld)
This way is more similar to how you usually run commands on the shell. To see the practical difference, you have to run ps ef from another shell with each solution.
If you want to run the script from everywhere you need to add it to your PATH. Usually /usr/local/bin is in the path of every user so this way it should work.
So check if in your system /usr/local/bin is in your PATH doing, on your terminal:
echo $PATH
You should see a lot of paths listed (like /bin, /sbin etc...). If its not listed you can add it. A even better solution is to keep all your scripts inside a directory, for example in your home and add it to your path.
To add a directory in your path you can modify your shell init scripts and add the new directories, for example if you're usin the BASH shell you can edi your .bashrc and add the line:
PATH=$PATH:/the_directory_you_want_to_add/:/another_directory/
This will append the new directories to your existing PATH.
You have to move it somewhere in your path. Try this:
echo $PATH
I bet /usr/local/bin is not listed.
I handle this by making a bin directory in my $HOME (i.e. mkdir ~/bin) and adding this to my ~/.bashrc file (make the file if you don't already have one):
export PATH=~/bin:$PATH
You can call your script using only the whole path, without the dot .:
/path/to/script
sudo also works fine:
sudo /path/to/script
Will they usually find all the stuff they need to run properly?
Do you mean like, "will my script find the files which are in the same folder?" That depends of your code. For example, if you have the script /tmp/test.sh:
#!/bin/bash
ls
If you invoke it from your home folder, it will run ls in your home:
test@ubuntu:~:/tmp/test.sh
Desktop Dropbox Imagens NetBeansProjects Público
Documentos Modelos R Vídeos
In this situation, dirname is your ally:
#!/bin/bash
current=$(dirname $0)
ls $current
Running it from your home folder, it gives:
test@ubuntu:~:/tmp/test.sh
acroread_1000_1000 hiRF7yLSOD pulse-2L9K88eMlGn7
unity_support_test.0 clementine-art-jt5332.jpg
which is the content of my /tmp/ folder.
Common *nix practice for user scripts is to put them in your bin directory. That way, the script will be searched for by default when you type the name from the command line.
Your bin (binary) directory should be in your home folder so the full path would be /home/yourusername/bin. (Obviously change yourusername to your login name.)
The bin directory should have the following permissions if you run ls -lh from the terminal: drwxr-xr-x
By default when you make a directory with the terminal you have the following permissions set: drwxrwxr-x
The only thing you need to change is the group permission, but for I will walk you through each step from the terminal (assuming you don't already have a bin):
Open a terminal ([Ctrl] + [Alt] + t)
Create the binary directory:
mkdir binNow either use the GUI or CLI to copy your scripts to
/bin.Now we have to change some permissions so that everything is set up correctly:
chmod -R 755 bin
This sets the owner (you) to read, write and execute, groups and others to read and execute the scripts. The -R means recursive or set the permissions for all the files in the directory as well.
For more help on file permissions see this document.
Now, you can just type myscript to execute your scripts - you do not have to be in the directory. You don't need the . / or anything!
For sudo it's a little different as you will have to define the full path to the script file.
The reason that your code does not work is because of what happens when a filename globbing pattern expands.
The pattern would expand to a list of matching pathnames. The code in your script would call sh with this list. This means it would execute the first matching name as the script and give the other names as arguments to that script:
sh /var/scripts/dir/my_first.inc.sh /var/scripts/dir/my_second.inc.sh /var/scripts/dir/my_third.inc.sh
Instead, just iterate over the matching names:
#!/bin/sh
for name in /var/scripts/*/my_*.inc.sh; do
sh "$name"
done
This assumes that each of the matching names is a script that should be executed by sh (not bash). If the individual files are executable and has a proper #!-line, then remove the sh from the invocation of the script in the loop above. If the files are "dot scripts", i.e. script that should be sourced, then replace sh by . instead to have the script execute in the current script's environment.
Note that the script above can be an sh script (#!/bin/sh) as it does not use any bash features. If the other script are "dot scripts", then you may obviously have to change this to #!/bin/bash or whatever other interpreter is needed to source the scripts.
A .inc.sh extension suggests those .inc.sh file should be included, or in other words, that their contents should be evaluated as shell code by one shell interpreter, so that that same shell interpreter can execute some other code with the functions, variables, aliases... defined in those files available.
bash's syntax is mostly backward compatible with the sh syntax, especially when its POSIX mode is enabled (bash is actually a sh interpreter when invoked as sh), so even though those functions are presumably written in sh language, you should still be able to have a bash interpreter interpret them.
One notable difference between bash (when not in POSIX mode) and sh is that bash doesn't enable alias expansion in scripts. That can be worked around though by setting the expand_aliases option or the posix option, so you can do:
#! /bin/bash -
set -o posix # increase POSIX sh compatibility, some but not all bash-specific
# extensions are still available.
for file in /var/scripts/*/my_*.inc.sh; do
. "$file"
done
# rest of the code that uses the functions/variables, etc defined
# in the files sourced above with the "." special builtin
Note that if there's no matching file, the . command will fail when trying to source a non-existing file called literally /var/scripts/*/my_*.inc.sh and exit the shell.
If instead in that case you wanted to not do anything you could do:
shopt -s nullglob
files=(/var/scripts/*/my_*.inc.sh)
shopt -u nullglob
for file in "${files[@]}"; do
command . "$file"
done
With nullglob, globs with no match expand to the empty list instead of the unexpanded pattern. With the command prefix, failure of special builtins like . (like when $file is not readable) doesn't cause the shell to exit (and error should still be reported).
To look for .inc.sh files recursively instead of just the subdirs of /var/scripts, you could use the globstar option to enable the ** operator:
shopt -s nullglob globstar
files=(/var/scripts/**/my_*.inc.sh)
shopt -u nullglob globstar
In any case, directory and files whose name starts with . (hidden ones) are omitted. Use the dotglob option if you want to include the,
Obviously, if any of the sourced scripts calls exit or exec or has a syntax error or any of the special builtins called within fail, that will also exit the script.
First confirm that the configure script is present where you think it is. Second make sure that it's executable:
$ ls -l ./configure
-rwxrwxr-x 1 saml saml 100 Jun 9 05:11 ./configure
If both of the checks are OK then you might want to try running configure by first changing directories to /mainfolder/execution and then running configure like this:
$ cd /mainfolder/execution
$ ../configure
You also might want to try it this way:
$ cd /mainfolder
$ ./configure execution
EDIT #1
According to comments left by OP, the following directory structure appears to be what he's describing:
$ tree -f
.
`-- /mainfolder
`-- /mainfolder/execution
`-- /mainfolder/execution/configure
In *nix / always is the root directory of the whole file system and . always refers to the current working directory.
Every path starting with / is an absolute path. Every path starting with . is a relative path.
Hence /home/... is probably correct, as this directory lives it the root directory, whereas /excecution is probably wrong as this directory does not live in the root directory, but somewhere under /home/....
If you say ./configure, you try to run the file configure living in the current working directory (.).
The error No such file or directory, well, just says that there is no file named configure in the current working directory.
You can use pwd to show, what the current working directory is. Use ls to show what files exist there. Use cd to change the current working directory.
To help you with your actual problem. You need to say what you were trying to do. Why do you want to run configure? What is it supposed to do? Why do you think you need to specify the execution directory?