A process isn't "killed with SIGHUP" -- at least, not in the strict sense of the word. Rather, when the connection is dropped, the terminal's controlling process (in this case, Bash) is sent a hang-up signal*, which is commonly abbreviated the "HUP signal", or just SIGHUP.
Now, when a process receives a signal, it can handle it any way it wants**. The default for most signals (including HUP) is to exit immediately. However, the program is free to ignore the signal instead, or even to run some kind of signal handler function.
Bash chooses the last option. Its HUP signal handler checks to see if the "huponexit" option is true, and if so, sends SIGHUP to each of its child processes. Only once its finished with that does Bash exit.
Likewise, each child process is free to do whatever it wants when it receives the signal: leave it set to the default (i.e. die immediately), ignore it, or run a signal handler.
Nohup only changes the default action for the child process to "ignore". Once the child process is running, however, it's free change its own response to the signal.
This, I think, is why some programs die even though you ran them with nohup:
- Nohup sets the default action to "ignore".
- The program needs to do some kind of cleanup when it exits, so it installs a SIGHUP handler, incidentally overwriting the "ignore" flag.
- When the SIGHUP arrives, the handler runs, cleaning up the program's data files (or whatever needed to be done) and exits the program.
- The user doesn't know or care about the handler or cleanup, and just sees that the program exited despite nohup.
This is where "disown" comes in. A process that's been disowned by Bash is never sent the HUP signal, regardless of the huponexit option. So even if the program sets up its own signal handler, the signal is never actually sent, so the handler never runs. Note, however, that if the program tries to display some text to a user that's logged out, it will cause an I/O error, which could cause the program to exit anyway.
* And, yes, before you ask, the "hang-up" terminology is left over from UNIX's dialup mainframe days.
** Most signals, anyway. SIGKILL, for instance, always causes the program to terminate immediately, period.
Introduction to resource limits
Resource limits in Unix-like systems are controlled by getrlimit()
and setrlimit()
system calls. These limits are configured per process and are inherited when a new process is spawn (e.g. by fork()
). It means that if you want to set a limit from a shell the command must be built into the shell (not executed as a child process). Really ulimit
is a builtin in many shells including ksh
and bash
.
The observed behaviour
The "builtin" nature of ulimit
explains the different behaviour in ksh
and bash
.
The limit for number of user processes (ulimit -u
) is set by setrlimit(RLIMIT_NPROC, ...)
syscall. In old versions of AIX RLIMIT_NPROC was not supported.<1> The support was added in AIX 6.1<2 section 5.4.4 Implemented changes> so the ulimit
in ksh
uses setrlimit64()
correctly. The bash
was probably compiled to be compatible with older version of AIX and is not able to control this limit.
Conclusion
You can use the ulimit
builtin from ksh
and all the child processes will inherit the configured limits. The shells and processes in general have nothing to do with enforcing and keeping the resource limits unless they explicitly call setrlimit()
.
Alternative
In AIX there is also an alternative which should work in older versions of AIX too:
chdev -l sys0 -a maxuproc=100
See: 3, 4
Best Answer
Command substitution
$(...)
turns output into arguments. It first needs the whole output, because it's not possibly to supply arguments dynamically one by one.