http://www.itworld.com/operating-systems/386139/unix-when-bash-script-asks-where-am-i
When a question like "How can a bash script tell you where it's located?" pops into your head, it seems like it ought to be a very easy question to answer. We've got commands like pwd, but ... pwd tells you where you are on the file system, not where the script you are calling is located. OK, let's try again. We have echo $0. But, no, that's not much better; that command will only show you the location of the script as determined by how you or someone else called it. If the script is called with a relative pathname like ./runme, all you will see is ./runme. Obviously if you are running a script interactively, you know where it is. But if you want a script to report its location regardless of how it is called, the question gets interesting.
So as not to keep you in suspense, I'm going to provide the answer to this question up front and then follow up with some insights into why this command works as it does. To get a bash script to display its location in the file system, you can use a command like this:
One thing worth noting is that the command uses two sets of parentheses. These cause the script to launch subshells. The inner subshell uses ${BASH_SOURCE[0]} which is the path to the currently executing script, as it was invoked. The outer subshell uses the cd command to move into that directory and pwd to display the location. Since these commands are subshells, nothing has changed with respect to the rest of the script. We just invoke the subshells to display the information we're looking for and then continue with the work of the script.
To get a feel for how subshells work, we can use one to run a command that changes to a different directory and displays that location. When the command is completed, we're still where we started from.
Clearly, other vital information concerning a script can be displayed using a series of echo commands -- all related to where we are when we run the script and how we call it.
If we run a script like the "args" script shown below, the answers will reflect how the script was invoked.
A bash reference such as this will provide some additional information on this and other bash variables:
When a question like "How can a bash script tell you where it's located?" pops into your head, it seems like it ought to be a very easy question to answer. We've got commands like pwd, but ... pwd tells you where you are on the file system, not where the script you are calling is located. OK, let's try again. We have echo $0. But, no, that's not much better; that command will only show you the location of the script as determined by how you or someone else called it. If the script is called with a relative pathname like ./runme, all you will see is ./runme. Obviously if you are running a script interactively, you know where it is. But if you want a script to report its location regardless of how it is called, the question gets interesting.
So as not to keep you in suspense, I'm going to provide the answer to this question up front and then follow up with some insights into why this command works as it does. To get a bash script to display its location in the file system, you can use a command like this:
echo "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"That's something of a "mouthful" as far a Unix commands go. What exactly is going on in this command? We're clearly echoing something and using the cd and the pwd command to provide the information. But what's going on with this command?
One thing worth noting is that the command uses two sets of parentheses. These cause the script to launch subshells. The inner subshell uses ${BASH_SOURCE[0]} which is the path to the currently executing script, as it was invoked. The outer subshell uses the cd command to move into that directory and pwd to display the location. Since these commands are subshells, nothing has changed with respect to the rest of the script. We just invoke the subshells to display the information we're looking for and then continue with the work of the script.
To get a feel for how subshells work, we can use one to run a command that changes to a different directory and displays that location. When the command is completed, we're still where we started from.
$ echo $(cd /tmp; pwd) /tmp $ pwd /home/shs/binThis is not entirely unlike what our location-reporting command is doing; it's just one level simpler.
Clearly, other vital information concerning a script can be displayed using a series of echo commands -- all related to where we are when we run the script and how we call it.
If we run a script like the "args" script shown below, the answers will reflect how the script was invoked.
#!/bin/bash echo "arguments ----> ${@}" echo "\$1 -----------> $1" echo "\$2 -----------> $2" echo "path to me ---> ${0}" echo "parent path --> ${0%/*}" echo "my name ------> ${0##*/}"For the two path variables, what we see clearly depends on how we call the script -- specifically, if we use a full path name, a variable will represents the full path (such as ~), or a relative path.
$ ~/bin/args first second arguments ----> first second $1 -----------> first $2 -----------> second path to me ---> /home/shs/bin/args parent path --> /home/shs/bin my name ------> args
$ ./args first second arguments ----> first second $1 -----------> first $2 -----------> second path to me ---> ./args parent path --> . my name ------> argsYou can use the location-reporting command in any script to display its full path. It will, however, follow and display symbolic links if they are used to invoke the script. Here, we see that a symlink points at our bin directory, but the script reports on the symlink:
$ ls -l scripts lrwxrwxrwx 1 shs staff 5 Dec 7 18:36 scripts -> ./bin $ ./scripts/args arguments ----> $1 -----------> $2 -----------> path to me ---> ./scripts/args parent path --> ./scripts my name ------> args arguments ----> $1 -----------> $2 -----------> path to me ---> ./scripts/args parent path --> ./scripts my name ------> argsWhen you use the location-reporting command, you get the full path for a script even if you call it with a relative path. Here's an example of a script that does nothing else:
#!/bin/bash echo "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"And here's the result. We call the script with ./wru (for "where are you") and the output will look something like this. Voila! We get the full path even though we invoked the script with a relative path:
$ ./wru /home/shs/binThe $BASH_SOURCE variable may seem like a one that's just popped into existence, but it's actually one of a number of bash variables, many of which are likely very familiar. But, as you'd guess from the [0] included in the command above, it's an array.
A bash reference such as this will provide some additional information on this and other bash variables:
http://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
No comments:
Post a Comment