How to change argv0 in bash so command shows up with different name in ps?
Asked Answered
E

8

26

In a C program I can write argv[0] and the new name shows up in a ps listing.

How can I do this in bash?

Exodus answered 15/7, 2010 at 0:10 Comment(5)
Do you mean that you want to run a bash shell script and have its name in ps come up as something other than "bash"?Turnspit
If I write a script called foo.sh, it shows up in ps as foo.sh. I want to have it show up as bar.sh.Exodus
btw i doubt writing argv0 is actually legal, especially if what you write is longer than the original, but I need to find a reference for thisCaul
It's easy with zsh: unix.stackexchange.com/a/170322/15513Comfrey
BASH_ARGV0Titled
E
10

I've had a chance to go through the source for bash and it does not look like there is any support for writing to argv[0].

Exodus answered 20/7, 2010 at 12:22 Comment(0)
S
35

You can do it when running a new program via exec -a <newname>.

Sublet answered 15/7, 2010 at 0:22 Comment(3)
+1: and to add to the above, you could have an "if $0 isn't what i want, then 'exec -a what_i_want'" at the top...Mciver
Doesn't seem to have any affect for me in Bash 4.0.33Overmatch
Unfortunately it doesn't affect the current shell. You have to open a new one using it.Sublet
E
12

Just for the record, even though it does not exactly answer the original poster's question, this is something trivial to do with zsh:

ARGV0=emacs nethack
Enamel answered 19/11, 2014 at 20:55 Comment(1)
That answer helped me a lot. Thanks!Ulmaceous
E
10

I've had a chance to go through the source for bash and it does not look like there is any support for writing to argv[0].

Exodus answered 20/7, 2010 at 12:22 Comment(0)
F
8

I'm assuming you've got a shell script that you wish to execute such that the script process itself has a new argv[0]. For example (I've only tested this in bash, so i'm using that, but this may work elsewhere).

#!/bin/bash

echo "process $$ here, first arg was $1"
ps -p $$

The output will be something like this:

$ ./script arg1
process 70637 here, first arg was arg1
  PID TTY           TIME CMD
70637 ttys003    0:00.00 /bin/bash ./script arg1

So ps shows the shell, /bin/bash in this case. Now try your interactive shell's exec -a, but in a subshell so you don't blow away the interactive shell:

$ (exec -a MyScript ./script arg1)
process 70936 here, first arg was arg1
  PID TTY           TIME CMD
70936 ttys008    0:00.00 /bin/bash /path/to/script arg1

Woops, still showing /bin/bash. what happened? The exec -a probably did set argv[0], but then a new instance of bash started because the operating system read #!/bin/bash at the top of your script. Ok, what if we perform the exec'ing inside the script somehow? First, we need some way of detecting whether this is the "first" execution of the script, or the second, execed instance, otherwise the second instance will exec again, and on and on in an infinite loop. Next, we need the executable to not be a file with a #!/bin/bash line at the top, to prevent the OS from changing our desired argv[0]. Here's my attempt:

$ cat ./script
#!/bin/bash

__second_instance="__second_instance_$$"
[[ -z ${!__second_instance} ]] && {
  declare -x "__second_instance_$$=true"
  exec -a MyScript "$SHELL" "$0" "$@"
}

echo "process $$ here, first arg was $1"
ps -p $$

Thanks to this answer, I first test for the environment variable __second_instance_$$, based on the PID (which does not change through exec) so that it won't collide with other scripts using this technique. If it's empty, I assume this is the first instance, and I export that environment variable, then exec. But, importantly, I do not exec this script, but I exec the shell binary directly, with this script ($0) as an argument, passing along all the other arguments as well ($@). The environment variable is a bit of a hack.

Now the output is this:

$ ./script arg1
process 71143 here, first arg was arg1
  PID TTY           TIME CMD
71143 ttys008    0:00.01 MyScript ./script arg1

That's almost there. The argv[0] is MyScript like I want, but there's that extra arg ./script in there which is a consequence of executing the shell directly (rather than via the OS's #! processing). Unfortunately, I don't know how to get any better than this.

Update for Bash 5.0

Looks like Bash 5.0 adds support for writing to special variable BASH_ARGV0, so this should become far simpler to accomplish.

(see release announcement)

Foldaway answered 27/4, 2014 at 23:23 Comment(0)
L
6
( exec -a foo bash -c 'echo $0' ) 
Leroylerwick answered 15/7, 2010 at 6:24 Comment(2)
This will restart the process. Not the same as writing to argv[0] to change the name.Exodus
Well, it forks a subshell, then replaces that subshell with the process started by exec. That's nearly identical to what happens when you simply type bash -c 'echo $0'Martita
B
3

ps and others inspect two things, none of which is argv0: /proc/PID/comm (for the "process name") and /proc/PID/cmdline (for the command-line). Assigning to argv0 will not change what ps shows in the CMD column, but it will change what the process usually sees as its own name (in output messages, for example).

To change the CMD column, write to /proc/PID/comm:

echo -n mynewname >/proc/$$/comm; ps

You cannot write to or modify /proc/PID/cmdline in any way.

Process can set their own "title" by writing to the memory area in which argv & envp are located (note that this is different than setting BASH_ARGV0). This has the side effect of changing /proc/PID/cmdline as well, which is what some daemons do in order to prettify (hide?) their command lines. libbsd's setproctitle() does exactly that, but you cannot do that in Bash without support of external tools.

Boice answered 2/12, 2021 at 18:1 Comment(1)
OK, that's cool!Fastening
C
0

I will just add that this must be possible at runtime, at least in some environments. Assigning $0 in perl on linux does change what shows up in ps. I do not know how that is implemented, however. If I can find out, i'll update this.

edit: Based on how perl does it, it is non-trivial. I doubt there is any bask built in way at runtime but don't know for sure. You can see how perl does sets the process name at runtime.

Caul answered 15/7, 2010 at 13:38 Comment(0)
C
-2

Copy the bash executable to a different name.

You can do this in the script itself...

cp /bin/bash ./new-name
PATH=$PATH:.
exec new-name $0

If you are trying to pretend you are not a shell script you can rename the script itself to something cool or even " " (a single space) so

exec new-name " "

Will execute bash your script and appears in the ps list as just new-name.

OK so calling a script " " is a very bad idea :)

Basically, to change the name

bash script

rename bash and rename the script.

If you are worried, as Mr McDoom. apparently is, about copying a binary to a new name (which is entirely safe) you could also create a symlink

ln -s /bin/bash ./MyFunkyName
./MyFunkyName

This way, the symlink is what appears in the ps list. (again use PATH=$PATH:. if you dont want the ./)

Coloratura answered 1/12, 2016 at 23:29 Comment(5)
I hope no newbies saw literally rename bash and rename the script. This I am sure would break many many things!Razorback
:) it does start with "Copy the bash executable to a different name." and the commands are clear. I do this quite a lot if I want a bin with a different name, breaks nothing to change the name of a binary, clearly you do need to leave /bin/bash where it is. Sometimes bins act differently according to the name used, but they usualy have default behaviour too. I do it with bash a lot since I hack bash code and compile my own versions.Coloratura
Hi Teknopaul, yes (I read it and understood), but you know how copy and paste SO champs operate - perhaps edit the answer to say WHY you copy Bash to another name ;) If someone changes the true bash... they will be in for a ride if they reboot and don't have prompt.Razorback
If they copy paste it is perfectly safe cp /bin/bash ./whatever does not do any damage. Answer does say why. If you want to change what appears in the ps list an obvious approach is to change the name of the binary you are calling. exec is there to let you replace a running processes, this is what the op asks. How would you phrase it? replace bin? change the name o bin? Give bash a new name? I personally find it annoying when you ask a technical question and someone answers "dont do that" your too noob.Coloratura
Why is this answer still left here! Like what all the comments warn about, it is a "no solution" and it can be misleading for newbies!Endogenous

© 2022 - 2024 — McMap. All rights reserved.