For a given process ID, what is the best/most direct way to determine the environment variables (e.g. PATH)? Must be able to query for any arbitrary environment variable. PATH is just the first example.
'lsof -a -p $PID -d cwd -F' gets some of it.
But, I don't see a way to get the PATH for the given PID, using lsof.
'ps -Ep $PID' gets some of it.
But, again, 'not comprehensive. It appears to give back only a portion of the 'environment' for the process.
On a number of other Linux/UNIX variants, you can look at '/proc//environ'. But, OS X apparently does not use that mechanism.
You should get this information (and a little extra) with ps -Eww $PID
The reason you were only seeing part of the environment is that ps will trim the output to fit your window (if going to stdout). Adding "ww" to the flags tells ps not to be concerned with window size.
Related
In my .profile (SUSE Linux with Korn shell) I have had the following code active for many years:-
case $0 in
-ksh|ksh)
set -o ignoreeof
set -a
set -o vi
PS1=$(print '\033[34m$(tput bold)ksh:$(hostname)->$(tput sgr0)\033[00m ')
PS2="continue-> "
PS3=": "
PS4="$0.$LINENO+ "
FCEDIT=/usr/bin/vi
HISTFILE=~/.histories/${TTY}_$(hostname)_ksh_his
HISTSIZE=500
EDITOR=/bin/vi
VISUAL=/bin/vi
TERM=gnome
set +a ;;
*) SHELL=${SHELL} ;;
But lately that PS1 entry has been causing some unexpected problems. When I source a file of ~3K environment variables and then try to get onto to a UGE compute host, the following error causes everything to break down:-
$ qrsh -V -j y -pe mt 1 -l "os_version=SUSE12.0,model=EMT3500,cpu_code=E5-2667v4" -P iheavy -now no
ksh: /usr/bin/tput: Argument list too long
ksh: /bin/hostname: Argument list too long
ksh: /usr/bin/tput: Argument list too long
ksh:->
If I request a CentOS system (os_version=CS7.0) I do not see the error--it is specific to SUSE. Also, if I eliminate the PS1 entry altogether, I can get onto a SUSE system without any errors. This is the simplest way to capture the bigger problem: when I issue a qsub for batch computing tasks, my .profile ends up partially initialized and jobs fail to launch.
I often change environments and shells, so color-coding my terminal prompt in a shell-specific and host/queue-specific way has always been helpful. I would rather not retire that PS1 entry just for one project that has such a long list of environment variable names.
I have done various searches and learned that increasing ulimit settings can sometimes help in situations like this; however, I tried that (increased stack size and number-of-open-files to their maximum) and the outcome did not change.
Is there a practical way to avoid this problem without removing the PS1 entry?
Say you have a shell command like
cat file1 | ./my_script
Is there any way from inside the 'my_script' command to detect the command run first as the pipe input (in the above example cat file1)?
I've been digging into it and so far I've not found any possibilities.
I've been unable to find any environment variables set in the process space of the second command recording the full command line, the command data the my_script commands sees (via /proc etc) is just _./my_script_ and doesn't include any information about it being run as part of a pipe. Checking the process list from inside the second command even doesn't seem to provide any data since the first process seems to exit before the second starts.
The best information I've been able to find suggests in bash in some cases you can get the exit codes of processes in the pipe via PIPESTATUS, unfortunately nothing similar seems to be present for the name of commands/files in the pipe. My research seems to be saying it's impossible to do in a generic manner (I can't control how people decide to run my_script so I can't force 3rd party pipe replacement tools to be used over build in shell pipes) but it just at the same time doesn't seem like it should be impossible since the shell has the full command line present as the command is run.
(update adding in later information following on from comments below)
I am on Linux.
I've investigated the /proc/$$/fd data and it almost does the job. If the first command doesn't exit for several seconds while piping data to the second command can you read /proc/$$/fd/0 to see the value pipe:[PIPEID] that it symlinks to. That can then be used to search through the rest of the /proc//fd/ data for other running processes to find another process with a pipe open using the same PIPEID which gives you the first process pid.
However in most real world tests I've done of piping you can't trust that the first command will stay running long enough for the second one to have time to locate it's pipe fd in /proc before it exits (which removes the proc data preventing it being read). So if this method will return any information is something I can't rely on.
So, I need to run a program, not keep track of its PID (in memory, at least), and later kill that program. Any ideas? My immediate thought was to tag the process with something I could find later, but that seems a bust. My next thought was to store on disk the PID, but I've no idea what the convention for that sort of thing is. Any ideas? Thanks!
Your program can create a directory under /var/run/ to store such files. For instance, if your program is myprog it might store its PID on startup in
/var/run/myprog/PID
If your program could have multiple instances running at the same time, you might use the PID itself in the file name, along with its startup time, to ensure a unique file name for each instance.
/var/run/myprog/201410302306.1283.pid
(Note that if you use the PID in the file name, it's up to you if you actually write the PID in the file itself; an empty file would suffice.)
The most straight forward (and common case) is, as you and chepner already mentioned, to store it in a pid file. For this:
If it's a system wide programm:
/var/run/prog.pid
If it's a system installed program that might be run multiple times:
/var/run/prog/prog_instance.pid
If it's a user local program:
$HOME/.prog/prog.pid
Other options might be to use pgrep for finding it as long as you can uniquely define the calling command. For example pass a dummy argument not used and use it for retrieval:
$ prog.sg --instance_1234 &
$ pgrep -f -- '--instance_1234'
3523
you can use start-stop-daemon to start a program and kill it later. It has a lot of options to find the programm, the most usefull is the --pid that stores and retrive the pid from a file in filesystem, usually in /var/run (pay attention to file system privileges to write in it).
See the man pages for more tips.
How do you extend the output of ps -fe in Solaris so that it displays more than 80 characters? My process has several arguments and the process name could not be displayed anymore.
You can't display them with the default ps (/usr/bin/ps) which is a SVR4 regular one.
To get the full argument line, use the BSD ps (UCB = University of California at Berkeley):
/usr/ucb/ps -alxwww
We have finally fixed this in Solaris; as of Solaris 11.3 SRU 5, all original argument vectors as well as the environment variables can be retrieved from /proc. ps will now print all of the command line.
Fixed in Solaris 11.3 SRU 5
The simple answer is that there is no way to reliably acquire the full arguments to processes on Solaris for processes owned by other users. If you have root or other privileged access you can use /usr/ucb/ps on older versions, and 'pargs' or similar tools on newer versions (there is no tool which works across all versions).
Essentially Solaris stores the original args at process start time, while most other platforms allow ps to access, via some means, the contents of argv at runtime for the process. This stored-copy is in a special kernel data structure with limited (80 byte) size. This also means that it's not possible for a program to modify the args post-start as displayed by ps for useful or nefarious means.
Thus, if you need to access the command line for portable purposes, such as pid checking, you will need to choose between enforcing a short command line via hacks like launching programs controlled execp paths without absolute paths, or you will need to forgo that portable functionality on Solaris.
you can use pargs PID
it will give you more information than ps
Try ps -efl. If that doesn't work (I don't have a Solaris box handy) you can also try ps -efl | cat (as some programs check whether they're outputting to a terminal to decide on their output width).
There are two sets of options available for ps. Others will chime in with the correct names ( ( maybe BSD and SRVn)?)
With the non-options-preceded-with-a-hyphen-version, you can do
ps auxww(w?) | grep ${PID} to extend the length of the command detail that is printed (again, notice NO leading '-' option indicator).
Note that in some cases you will see a lot of environment variable assignments before the actually command, i.e. myPath=... cfgFile=... /path/to/command ... args ...
I think that 'www' in some systems will print everything, regardless how long the command is.
Finally, in my experience using ps to do a lot of crazy things, I would ocassionally have a PID and the output would display the first 6? columns, but the space reserved for the command was empty or had some sort of place holder value. I eventually found out why that was true, by searching comp.unix.shell, but it's too long ago now to be sure and I don't have access to Solaris systems right now.
I hope this helps.
I once read that one way to obtain a unique filename in a shell for temp files was to use a double dollar sign ($$). This does produce a number that varies from time to time... but if you call it repeatedly, it returns the same number. (The solution is to just use the time.)
I am curious to know what $$ actually is, and why it would be suggested as a way to generate unique filenames.
$$ is the process ID (PID) in bash. Using $$ is a bad idea, because it will usually create a race condition, and allow your shell-script to be subverted by an attacker. See, for example, all these people who created insecure temporary files and had to issue security advisories.
Instead, use mktemp. The Linux man page for mktemp is excellent. Here's some example code from it:
tempfoo=`basename $0`
TMPFILE=`mktemp -t ${tempfoo}` || exit 1
echo "program output" >> $TMPFILE
In Bash $$ is the process ID, as noted in the comments it is not safe to use as a temp filename for a variety of reasons.
For temporary file names, use the mktemp command.
$$ is the id of the current process.
Every process in a UNIX like operating system has a (temporarily) unique identifier, the PID. No two processes running at the same time can have the same PID, and $$ refers to the PID of the bash instance running the script.
This is very much not a unique idenifier in the sense that it will never be reused (indeed, PIDs are reused constantly). What it does give you is a number such that, if another person runs your script, they will get a different identifier whilst yours is still running. Once yours dies, the PID may be recycled and someone else might run your script, get the same PID, and so get the same filename.
As such, it is only really sane to say "$$ gives a filename such that if someone else runs the same script whist my instance is still running, they will get a different name".
$$ is your PID. It doesn't really generate a unique filename, unless you are careful and no one else does it exactly the same way.
Typically you'd create something like /tmp/myprogramname$$
There're so many ways to break this, and if you're writing to locations other folks can write to it's not too difficult on many OSes to predict what PID you're going to have and screw around -- imagine you're running as root and I create /tmp/yourprogname13395 as a symlink pointing to /etc/passwd -- and you write into it.
This is a bad thing to be doing in a shell script. If you're going to use a temporary file for something, you ought to be using a better language which will at least let you add the "exclusive" flag for opening (creating) the file. Then you can be sure you're not clobbering something else.
$$ is the pid (process id) of the shell interpreter running your script. It's different for each process running on a system at the moment, but over time the pid wraps around, and after you exit there will be another process with same pid eventually.As long as you're running, the pid is unique to you.
From the definition above it should be obvious that no matter how many times you use $$ in a script, it will return the same number.
You can use, e.g. /tmp/myscript.scratch.$$ as your temp file for things that need not be extremely reliable or secure. It's a good practice to delete such temp files at the end of your script, using, for example, trap command:
trap "echo 'Cleanup in progress'; rm -r $TMP_DIR" EXIT
$$ is the pid of the current shell process. It isn't a good way to generate unique filenames.
It's the process ID of the bash process. No concurrent processes will ever have the same PID.
The $$ is the process id of the shell in which your script is running. For more details, see the man page for sh or bash. The man pages can be found be either using a command line "man sh", or by searching the web for "shell manpage"
Let me second emk's answer -- don't use $$ by itself as a "unique" anything. For files, use mktemp. For other IDs within the same bash script, use "$$$(date +%s%N)" for a reasonably good chance of uniqueness.
-k
In Fish shell (3.1.2):
The $ symbol can also be used multiple times, as a kind of "dereference" operator (the * in C or C++)
set bar bazz
set foo bar
echo $foo # bar
echo $$foo # same as echo $bar → bazz
Also, You can grab login username via this command. Eg.
echo $(</proc/$$/login id). After that, you need to use getent command.