I'm writing a script to compile a code. The sources are in many different directories. I'm going to release the source and I want it to be compiled by many other people. Thus in my script I use relative paths.
If someone runs the script on his machine, from the directory the script is in, like ./script
everything is ok. But, if the script is being run from another directory, like ./path/to/script
then the paths are not correct and the script doesn't work.
How can I overcome this?
A relative path starts with / , ./ or ../ . To get a relative path in Python you first have to find the location of the working directory where the script or module is stored. Then from that location, you get the relative path to the file want.
Using relative file paths for your PowerShell script's supporting files ensure it continues to work when the script and files get moved around.
Relative path Relative paths make use of two special symbols, a dot (.) and a double-dot (..), which translate into the current directory and the parent directory. Double dots are used for moving up in the hierarchy. A single dot represents the current directory itself.
Absolute and Relative file pathsAbsolute file paths are notated by a leading forward slash or drive label. For example, /home/example_user/example_directory or C:/system32/cmd.exe. An absolute file path describes how to access a given file or directory, starting from the root of the file system.
#!/bin/bash
scriptdir="$(dirname "$0")"
cd "$scriptdir"
All following code will occur as if it was run inside the script dir.
Note that this is about causing the script to run
Which is what I suspect you want given that it's a script for compiling, thus it would placed in a very specific folder in the src tree (like a configure
script or a form of makefile for example)
$0
is the full path of the running script.
bash
man (my added formatting):
Special Parameters
The shell treats several parameters specially. These parameters may only be referenced; assignment to them is not allowed.
....
0 Expands to the name of the shell or shell script. This is set at shell initialization.
If bash is invoked with a file of commands, $0 is set to the name of that file.
If bash is started with the-c
option, then $0 is set to the first argument after
the string to be executed, if one is present. Otherwise, it is set to the file name
used to invoke bash, as given by argument zero.
dirname
returns the path of its argument
cd
changes the current directoryTherefore, every script with this code at the top, will be running as if ./script
was typed while currently in that directory.
For measures of quality control and redundant error checking, you may want to implement a wrapper function that checks for a specific folder structure or presence of certain files that indicates everything is correct. (Say for whatever reason that dirname
and cd
command didn't work - which I have an example of for Mac down the bottom of this post). This concept is two fold:
For example:
runcheck () {
versioncheck () {
head -n1 version | grep -q "### myapp V"
}
backout () {
echo "Problem verifying source paths. Are you sure your archive is complete?"
exit
}
[ -d ./src ] && [ -d ./docs ] && [ -d ../myapp ] && (versioncheck) || backout
return
}
That code would check the following:
src
exists in the same path as the executable scriptdocs
exists in the same path as the executable scriptmyapp
exists in the path one level down from the executable scriptversion
in the same path as the executable script, and that it's first line contains the string ### myapp V
(for example, for a version
file which might have a top line that reads: ### myapp V1.4 ###
)You could then place the command runcheck
at any point in your script where it's important to verify you're in the right place:
#!/bin/bash
scriptdir="$(dirname "$0")"
cd "$scriptdir"
runcheck () {
versioncheck () {
head -n1 version | grep -q "### myapp V"
}
backout () {
echo "Problem verifying source paths. Are you sure your archive is complete?"
exit
}
[ -d ./src ] && [ -d ./docs ] && [ -d ../myapp ] && (versioncheck) || backout
return
}
runcheck #initial check at start of script
## bunch of code
## goes here
runcheck #just checking again
## bunch of code
## goes here
runcheck #final check before really doing something bad
## end of script
Side Note / Supplement: This will work for bash
when no thorough checking needs to occur to account for symbolic linking of the scriptfile, etc.. (which again... in portable source code tarballs, etc, I highly doubt is the case).
I suggest reading this thread: Getting the source directory of a Bash script from within if you want or ever need a thorough understanding on this topic for more comprehensive applications of it.
Again I re-inforce using what you know tailored for what you need - for example it might be considered generally more "robust" to use dirname "$(readlink -f "$0")"
, however, on Mac OS X, that would give you readlink: illegal option -- f
, and is of no real benefit for portable scripts but more applicable for referencing locations of installed binaries that may be symlinked and/or contained in $PATH dirs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With