How to find path from where current process/executable is running? - unix

I am running some executables while connected to a local unix server box.
Say, I'm trying to run an executable 'abc'. Now the server might have provided an alias for 'abc'.. How do I get to know of this path? As in, if I invoke 'abc', it might actually run it from, say, /opt/corp/xyz/abc .. How do I get to know from what path I'm invoking the executable?
By the way I'm running on HP-UX :D

"which abc" to show which abc you would be calling
or "alias" to list aliases
perhaps "echo $0" from inside a script, or retrieving argv[0] some other way.

If you are running using the PATH environment variable, you could try:
$ which abc
or
$ whereis abc
If there is a symbolic link for the command and you want to know the "real" target, you can use something like:
$ readlink /opt/corp/xyz/abc
I do not have access to an HPUX system in front of me right now, but this should work:
$ ls -l /opt/local/bin/wish
lrwxr-xr-x 1 root admin 22 Feb 3 21:56 /opt/local/bin/wish# -> /opt/local/bin/wish8.5
$ readlink /opt/local/bin/wish
/opt/local/bin/wish8.5
If the command is based on an alias, the following will reveal the alias definition.
$ alias abc
depending on how your system is configured, the above commands should provide answers to multiple variations of your question.
in Perl:
$running_script = $0;
from Python, see SO How to get filename of the __main__ module in Python?

Does HP-UX have the "which" command? Run:
which abc
If you have it, the which command will tell you which abc program will run from your $PATH.

Thanks all!
'which' was the commmand I was after! I'm facepalming myself now as I had already known the command (in Ubuntu)..
And it does work like a charm in HP-UX!
EDIT : 'whereis' suggested by popcnt is even more appropriate!
Thanx a lot man!

From a command line terminal:
$ which abc
/opt/corp/xyz/abc

The correct way to get the path of a script on Unix is:
dir=$(cd $(dirname "$0"); pwd)
Background: $0 is the filename+path of the script relative to the current directory. It can be absolute (/...) or relative (../, dir/...). So the $(dirname "$0") returns the path (without the filename). Mind the quotes; "$0" can contain spaces and other weird stuff.
We then cd into that directory and pwd will return the absolute path where we end up.
Works for ksh and bash.
In a C program, you should check argv[0]. I'm not sure whether the shell will put the complete path in there. If you have trouble, I suggest to wrap your executable in a small script which prepares the environment and then invoke your executable with:
exec "$dir/"exe "$#"

Related

Filter command history by folder they were executed in?

I know shell history doesn't keep track of the folder the commands were executed in but I think it would be really useful to be able to output the history for a particular folder by using a flag like history --local for example.
I often jump from project to project which use very similar commands but have different destination host for ssh or environment variable...
Is there any way to achieve that –preferably using zsh?
In bash, you can set PROMPT_COMMAND to something like the following:
PROMPT_COMMAND='history | tail -n1 >> .$USER.history'
It will save each command to a file in the current directory.
For an alternative approach (replacing cd with a command that changes where history is saved), see http://www.compbiome.com/2010/07/bash-per-directory-bash-history.html.

Correct Wildcard Notation for UNIX systems?

I am currently trying to remove a number of files from my root directory. There are about 110 files with almost the exact same file name.
The file name appears as wp-cron.php?doing_wp_cron=1.93 where 93 is any integer from 1-110.
However when I try to run the code: sudo rm /root/wp-cron.php?doing_wp_cron=1.* it actually tries to find the file with the asterisk * in the filename, leaving me with a file not found error.
What is the correct notation for removing a series of files using wildcard notation?
NOTE: I have already tried delimiting the filepath with both single ' and double quotes ". This did not avail.
Any thoughts on the matter?
Take a look at the permission on the /root directory with ls -ld /root, typically a non-root user will not have r-x permissions, which won't allow them to read the directory listing.
In your command sudo rm /root/wp-cron.php?doing_wp_cron=1.* the filename expansion attempt happens in the shell running under your non-root user. That fails to expand to the individual filenames as you do not have permissions to read /root.
The shell then execs sudo\0rm\0/root/wp-cron.php?doing_wp_cron=1.*\0. (Three separate, explicit arguments).
sudo, after satisfying its conditions, execs rm\0/root/wp-cron.php?doing_wp_cron=1.*\0.
rm runs and attempts to unlink the literal path /root/wp-cron.php?doing_wp_cron=1.*, failing as you've seen.
The solution to removing depends on your sudo permissions. If permitted, you may run a bash sub-process to do the file-name expansion as root:
sudo bash -c "rm /root/a*"
If not permitted, do the sudo rm with explicit filenames.
Brandon,
I agree with #arkascha . That glob should match, so something is amiss here. Do you get the appropriate list of files if you use a different binary, say 'ls' ? Try this:
ls /root/wp-cron.php?doing_wp_cron=1.*
If that returns the full list of files, then you know there's something funny with your environment regarding rm. This could be an alias as suggested.
If you cannot determine what is different or wrong with your environment you could run the list of files through a for loop and remove each one as a work-around:
for file in `ls /root/wp-cron.php?doing_wp_cron=1.*`
do
rm $file
done

Problem: Unable to execute the correct executable file in Unix

I am encountering a really strange problem, any help is appreciated.
I have a executable file compiled and cp to a specific location. The name of this executable is "qact" There is a newly added cout statement at the first line of the main function. But when I execute the binary file in that directory, i can not see it. After a long while I accidentally find out that if I am not in that directory, I can see the outputed string when i execute it.
And later I find out that it's only when I am in that directory, the executed binary file is wrong and I will not see the string.
when I use which on that executable, no mater what directory I am in, I always get the same result and it is the correct location.
Really confused..
Do you have another executable file of the same name elsewhere in your $PATH? If so, it's possible that bash is executing the wrong executable because it uses a hash table to avoid extra $PATH lookups (see Command Search and Execution).
For example, suppose your $PATH is /opt/local/bin:/usr/bin, and you have grep installed in only /usr/bin. When you execute grep, you get the obvious result:
$ echo $PATH
/opt/local/bin:/usr/bin
$ which grep
/usr/bin/grep
$ grep --version
grep (GNU grep) 2.5.1
Now suppose that you install a newer version of grep into /opt/local/bin, which is earlier in your $PATH than /usr/bin. Because which always does the full $PATH lookup each time, but bash keeps a hash table, bash still thinks that the command grep maps to the one in /usr/bin:
$ which grep
/opt/local/bin/grep
$ grep --version
grep (GNU grep) 2.5.1
$ /opt/local/bin/grep --version
GNU grep 2.6.3
You can use the type builtin to diagnose this problem. type will tell you if a command is a shell builtin, an alias, a function, a keyword, or an executable file. If the latter, it tells you the full path to the executable:
$ type grep
grep is hashed (/usr/bin/grep)
So how do you fix this? You can use the hash builtin to manipulate the hash table (type help hash for more information). If you just want to fix one entry (grep in this case), you can do hash -d grep to say "delete the hash table entry for grep", in which case the next time you execute grep, it will search the full $PATH as expected. If you want to clear out the entire hash table (say, if you just installed a large amount of new software or you changed your $PATH), then use hash -r to empty it.

shell built in pwd versus /bin/pwd

I would like to know the code implementation of built-in pwd and /bin/pwd especially when the directory path is a symbolic link.
Example:
hita#hita-laptop:/home$ ls -l
lrwxrwxrwx 1 root root 31 2010-06-13 15:35 my_shell -> /home/hita/shell_new/hita_shell
hita#hita-laptop:/home$ cd my_shell
hita#hita-laptop:/home/my_shell$ pwd <SHELL BUILT-IN PWD>
/home/my_shell
hita#hita-laptop:/home/my_shell$ /bin/pwd
/home/hita/shell_new/hita_shell
The output is different in both the cases. Any clue?
thanks
The kernel maintains a current directory (by inode) and when you need the current directory, it determines its name by walking up the directory tree (using ..) to find the names of all the path components. This is the 'real' or sometimes called 'physical' working directory. There is a library function getcwd(3) which does this for you; on more-recent Linux systems this is actually a system call, which helps with getting a consistent view should the parent directories be in the process of being renamed.
Some shells, notably bash, maintain a environment variable PWD to keep track of where you are, and if you changed directory through a symbolic link, this environment variable will show that. They call this the 'logical' path.
/bin/pwd shows the result of getcwd(3), ie the real path; if you give it -L it will tell you the value of PWD (unless it's rubbish, then you get the real path). (Gnu's version of /bin/pwd does more work than this to deal with complexities of parent directories without read permission and very long path names.)
Bash's built-in pwd shows you the 'logical' path with whatever symlinks you used to get there; even if it's now rubbish (ie deleted or renamed since you used it). The default of the built-in pwd can be changed with set -o physical (on) or set +o physical (off is plus!) The default prompt (containing the current directory) follows the option too.
# make a directory with a symlink alias
cd /tmp
mkdir real
ln -s real sym
cd sym
pwd # will say sym
pwd -L # will say sym
pwd -P # will say real
/bin/pwd # will say real
/bin/pwd -L # will say sym
/bin/pwd -P # will say real
rm /tmp/sym
pwd # says sym, though link no longer exists
/bin/pwd -L # will say real!
rmdir /tmp/real
pwd # says sym, though no directory exists
/bin/pwd # says error, as there isn't one
For what it's worth, my opinion is that all the 'logical' business is just adding to the confusion; the old way was the better way. It's true that symbolic links can be confusing, but this makes it more confusing, because any file operations which open .. don't do the same thing as any directory changes which use .. for example in this rather nasty example:
mkdir -p /tmp/dir/subdir
ln -s /tmp/dir/subdir /tmp/a
cd /tmp/a
ls .. # shows contents of /tmp/dir
(cd .. ; ls) # shows contents of /tmp
To avoid all this, you can put the following in your ~/.bashrc
set -o physical
Hope that helps!
Kind regards,
J.
PS The above is pretty specific to Linux and Gnu bash; other shells and systems are similar but different.
The shell's builtin pwd has the advantage of being able to remember how you accessed the symlinked directory, so it shows you that information. The standalone utility just knows what your actual working directory is, not how you changed to that directory, so it reports the real path.
Personally, I dislike shells that do what you're describing because it shows a reality different than that which standalone tools will see. For example, how a builtin tool parses a relative path will differ from how a standalone tool parses a relative path.
The shell keeps track in its own memory what your currenct directory is by concatenating it with whatever you cd to (and eliminating . and .. entries). It does this so that symbolic links don't mess up cd ... The /bin/pwd implementation walks the directory tree upwards trying to find inodes with the right names.
The built-in pwd shows symbolic links by default, but won't do if you give it the -P option.
In contrast, the pwd command doesn't show symbolic links by default, but will do if given the -L option.

`(cd X; pwd)` sometimes returns two-line

I have shell script which starts with:
sdir=`dirname $0`
sdir=`(cd "$sdir/"; pwd)`
And this usually gets expanded (with 'sh -h') into
++ dirname /opt/foo/bin/bar
+ sdir=/opt/foo/bin
++ cd /opt/foo/bin/
++ pwd
+ sdir=/opt/foo/bin
but for single user for single combination of parameters in expands into (note two lines at the result sbin value)
++ dirname bin/foo
+ sdir=bin
++ cd bin/
++ pwd
+ sdir='/opt/foo/bin
/opt/foo/bin'
I tried different combinations but was not able to reproduce this behavior. With different input parameters for that user it started producing correct single line result. I am new to shell scripting, so please advice when such (cd X; pwd) can return two line.
it was observed on CentOS, but not sure it that matters. Please advice.
The culprit is cd, try this instead
sdir=`dirname $0`
sdir=`(cd "$sdir/" >/dev/null; pwd)`
This happens because when you specify a non absolute path and the directory is found in the environment variable CDPATH, cd prints to stdout the value of the absolute path to the directory it changed to.
Relevant man bash sections:
CDPATH The search path for the cd command. This is a
colon-separated list of directories in which the
shell looks for destination directories specified
by the cd command. A sample value is ``.:~:/usr''.
cd [-L|-P] [directory]
Change the current working directory to directory. If
directory is not given, the value of the HOME shell
variable is used. If the shell variable CDPATH exists,
it is used as a search path. If directory begins with a slash,
CDPATH is not used.
The -P option means to not follow symbolic links; symbolic
links are followed by default or with the -L option. If
directory is ‘-’, it is equivalent to $OLDPWD.
If a non-empty directory name from CDPATH is used, or if ‘-’
RELEVANT -\ is the first argument, and the directory change is successful,
PARAGRAPH -/ the absolute pathname of the new working directory is written
to the standard output.
The return status is zero if the directory is successfully
changed, non-zero otherwise.
OLDPWD The previous working directory as set by the cd
command.
CDPATH is a common gotcha. You can also use "unset CDPATH; export CDPATH" to avoid the problem in your script.
It's possible that user has some funky alias for "cd". Perhaps you could try making it do "/usr/bin/cd" (or whatever "cd" actually runs by default) instead.
Some people alias pwd to "echo $PWD". Also, the pwd command itself can either be a shell built-in or a program in /usr/bin. Do an "alias pwd" and "which pwd" on both that user and any user that works normally.
Try this:
sdir=$( cd $(dirname "$0") > /dev/null && pwd )
It's just a single line and will keep all special characters in the directory name intact. Remember that on Unix, only two characters are illegal in a file/dir name: 0-byte and / (forward slash). Especially, newlines are valid in a file name!

Resources