Everytime I run ps, it returns the usual PID and CMD, but - bash

In every book I've read, it never returns like this:
PID CMD
2748 -bash
8114 awk
7900 -bash
Which is what my ps returns. Is that normal for the - to be in front of the bash? I've only ever seen 2290 bash, never without the - in front of it. Trivial question, but I assume it isn't normal. Thank you, and sorry for the stupid question.

This means a login shell. Take a look at man bash:
A login shell is one whose first character of argument zero is a -, or one started with the --login option.
If you run cat /proc/2748/cmdline you will see the hyphen there. This is where ps is getting it from.
-f will look at /proc/[pid]/cmdline, whereas by default it will look at /proc/[pid]/comm.
tom#riki:~$ ps
PID TTY TIME CMD
9230 pts/2 00:00:00 bash
9429 pts/2 00:00:00 ps
tom#riki:~$ ps -f
UID PID PPID C STIME TTY TIME CMD
tom 9230 9229 0 17:39 pts/2 00:00:00 -bash
tom 9427 9230 0 18:22 pts/2 00:00:00 ps -f
tom#riki:~$ cat /proc/9230/comm
bash
tom#riki:~$ cat /proc/9230/cmdline
-bash

Related

Executing a shell with a command and returning

man bash seems to suggest that if I want to execute a command in a separate bash shell all I have to do is bash -c command:
-c string If the -c option is present, then commands are read from string.
I want to do that because I need to run a few things in different environments:
bash --rcfile ~/.bashrc.a -c mytest.a
bash --rcfile ~/.bashrc.b -c mytest.b
However, that didn't work as expected; one can see that by the number of bash shells running, for example:
$ bash
$ ps
PID TTY TIME CMD
7554 pts/0 00:00:00 bash
7573 pts/0 00:00:00 ps
28616 pts/0 00:00:00 bash
$ exit
exit
$ ps
PID TTY TIME CMD
7582 pts/0 00:00:00 ps
28616 pts/0 00:00:00 bash
$ bash -c ps
PID TTY TIME CMD
7583 pts/0 00:00:00 ps
28616 pts/0 00:00:00 bash
How should the invocation of bash should be modified so that it would start a new shell with the specified rc, execute the given command in that shell (with the env modified according to the rc), and exit back?
It's already working exactly the way you want it to. The lack of an extra process is simply due to bash's tail-call optimization.
Bash recognizes that there's no point in having a shell instance whose only job is to wait for a process and exit. It will instead skip the fork and exec the process directly. This is a huge win for e.g. var=$(ps), where it cuts the number of expensive forks from 2 to 1.
If you give it additional commands to run afterwards, this optimization is no longer valid, and then you'll see the additional process:
$ bash -c 'ps'
PID TTY TIME CMD
4531 pts/10 00:00:00 bash
4540 pts/10 00:00:00 ps
$ bash -c 'ps; exit $?'
PID TTY TIME CMD
4531 pts/10 00:00:00 bash
4549 pts/10 00:00:00 bash
4550 pts/10 00:00:00 ps
bash --rcfile ~/.bashrc.a mytest.a will already run mytest.a in a separate process. -c is for specifying a shell command directly, rather than running a script.
# NO!
bash for x in 1 2 3; do echo "$x"; done
# Yes.
bash -c 'for x in 1 2 3; do echo "$x"; done'

Why does `cat <(cat)` produce EIO?

I have a program that reads from two input files simultaneously. I'd like to have this program read from standard input. I thought I'd use something like this:
$program1 <(cat) <($program2)
but I've just discovered that
cat <(cat)
produces
....
mmap2(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb758e000
read(0, 0xb758f000, 131072) = -1 EIO (Input/output error)
....
cat: -: Input/output error
and similarly,
$ cat <(read -n 1)
bash: read: read error: 0: Input/output error
So... Linux is failing to read at the syscall level. That's interesting. Is bash not wiring stdin to the subshell? :(
Is there a solution to this? I specifically need to use process substitution (the ... <(...) format) because $program1 (tail, incidentally) expects files, and I need to do some preprocessing (with od) on standard input before I can pass it to tail - I can't just specify /dev/stdin et al.
EDIT:
What I actually want to do is read from a file (which another process will be writing to) while I also read from standard input so I can accept commands and such. I was hoping I could do
tail -f <(od -An -vtd1 -w1) <(cat fifo)
to read from standard input and the FIFO simultaneously and drop that into a single stdout stream I could run through awk (or similar). I know I could solve this trivially in any scripting language, but I like learning how to make bash do everything :P
EDIT 2: I've asked a new question that more fully explains the context I described just above.
1. Explain why cat <(cat) produces EIO
( I'm using Debian Linux 8.7, Bash 4.4.12 )
Let's replace <(cat) with the long running <(sleep) to see what's happening.
From pty #1:
$ echo $$
906
$ tty
/dev/pts/14
$ cat <(sleep 12345)
Go to another pty #2:
$ ps t pts/14 j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
903 906 906 906 pts/14 29999 Ss 0 0:00 bash
906 29998 906 906 pts/14 29999 S 0 0:00 bash
29998 30000 906 906 pts/14 29999 S 0 0:00 sleep 12345
906 29999 29999 906 pts/14 29999 S+ 0 0:00 cat /dev/fd/63
$ ps p 903 j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 903 903 903 ? -1 Ss 0 0:07 SCREEN -T linux -U
$
Let me explain it (according to the APUE book, 2nd edition):
The TPGID being 29999 indicates that cat (PID 29999) is the foreground process group which is now controlling the terminal (pts/14). And sleep is in the background process group (PGID 906).
The process group of 906 is now an orphaned process group because "the parent of every member is either itself a member of the group or is not a member of the group’s session". (The PID 906's PPID is 903 and 903 is in a different session.)
When the process in an orphaned background process group reads from its controlling terminal, read() would fail with EIO.
2. Explain why cat <(cat) sometimes works (not really!)
Daniel Voina mentioned in a comment that cat <(cat) works on OS X with Bash 3.2.57. I just managed to reproduce it also on Linux with Bash 4.4.12.
From pty #1:
bash-4.4# echo $$
10732
bash-4.4# tty
/dev/pts/0
bash-4.4# cat <(cat)
cat: -: Input/output error
bash-4.4#
bash-4.4#
bash-4.4# bash --norc --noprofile # start a new bash
bash-4.4# tac <(cat)
<-- It's waiting here so looks like it's working.
(The first cat <(cat) failing with EIO was explained in the first part of my answer.)
Go to another pty #2:
bash-4.4# ps t pts/0 j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
10527 10732 10732 10732 pts/0 10805 Ss 0 0:00 bash
10732 10803 10803 10732 pts/0 10805 S 0 0:00 bash --norc --noprofile
10803 10804 10803 10732 pts/0 10805 S 0 0:00 bash --norc --noprofile
10804 10806 10803 10732 pts/0 10805 T 0 0:00 cat
10803 10805 10805 10732 pts/0 10805 S+ 0 0:00 tac /dev/fd/63
bash-4.4# ps p 10527 j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
10526 10527 10527 10527 ? -1 Ss 0 0:00 SCREEN -T dtterm -U
bash-4.4#
Let's see what's happening:
The TPGID being 10805 indicates that tac (PID 10805) is the foreground process group which is now controlling the terminal (pts/0). And cat (PID 10806) is in the background process group (PGID 10803).
But this time the pgrp 10803 is not orphanded because its member PID 10803 (bash)'s parent (PID 10732, bash) is in another pgrp (PGID 10732) and it's in the same session (SID 10732).
According to the APUE book, SIGTTIN will be "generated by the terminal driver when a process in a (non-orphaned) background process group tries to read from its controlling terminal". So when cat reads stdin, SIGTTIN will be sent to it and by default this signal would stop the process. That's why the cat's STAT column was shown as T (stopped) in the ps output. Since it's stopped the data we input from keyboard are not sent to it at all. So it just looks like it's working but it's not really.
Conclusion:
So the different behaviors (EIO vs. SIGTTIN) depend on whether the current Bash is a session leader or not. (In the 1st part of my answer, the bash of PID 906 is the session leader, but the bash of PID 10803 in the 2nd part is not the session leader.)
The accepted answer explained why, but I saw one solution which can solve it. It is by subshelling it with additional (), such as:
(cat <(cat))
Please find the solution details here:
https://unix.stackexchange.com/a/244333/89706

xterm -e not terminating when script finishes execution

I'm running two levels of xterms. In the first level I run "xterm -e bsub -Ip master.tcl". The master.tcl script invokes yet another xterm with "xterm -e bsub -Ip slave.tcl".
From some reason, when slave.tcl finishes executing, the second xterm is not closing. However, the second xterm does display the following message once the slave script finishes:
<< JobExitInfo: Job <128309> is done successfully. >>
Also, when looking at the LSF system, the job does not appear, as if it really finished. But the xterm window stays open, instead of closing.
Any idea why?
Thanks.
It is unlikely that xterm would stay open unless there was something still running there.
I'd check (using ps -ef for instance) to see what processes are still running in the remaining xterm. xterm would only be still open if there were something running, e.g., waiting for input.
Using ps -ef (assuming this is not a BSD system), you would see a listing with a heading like this:
UID PID PPID C STIME TTY TIME CMD
and later in the listing, the relevant information, e.g.,
tom 3647 20185 0 06:17 pts/2 00:00:00 sh -c xterm -e vile
tom 3648 3647 0 06:17 pts/2 00:00:00 xterm -e vile
tom 3649 3648 0 06:17 pts/3 00:00:00 vile
tom 3650 3649 0 06:17 pts/3 00:00:00 sh -c ps -ef
tom 3651 3650 0 06:17 pts/3 00:00:00 ps -ef
xterm's process-id (PID) is the place to start. It would be found in the PPID (parent's process-ID) column at least one other place. In turn, that process's PID may be used in further child-processes.
BSD systems use a different set of options (see FreeBSD for example), but in general you can obtain the necessary information from ps.

Why does echo $$ return a number? [duplicate]

This question already has answers here:
What are the special dollar sign shell variables?
(4 answers)
Closed 8 years ago.
Why do I get a number when doing that :
echo $$
which returns
489
If I open a new terminal it returns another number. It seems it's related to the pid of the terminal session, but why ?
$$ means your current PID.
As seen in Bash Reference Manual - 3.4.2 Special Parameters:
$
Expands to the process ID of the shell. In a () subshell, it expands
to the process ID of the invoking shell, not the subshell.
You can test it by doing ps -ef | grep 489, and it will show the process in which you are logged in.
For example in my case:
$ echo $$
3470
$ ps -ef | grep 3470
1000 3470 3469 0 10:59 pts/3 00:00:00 -bash <---- this process
1000 8151 3470 0 15:37 pts/3 00:00:00 ps -ef
1000 8152 3470 0 15:37 pts/3 00:00:00 grep --color=auto 3470
Because that's how it is defined. $$ is a special shell variable (like e.g. $!, $_, $#, $1, ...) referring to the PID of the invoked shell.
You will find an excellent explanation in this post.
$$ pid of the current shell (not subshell)

command substitution in RUBY

Please explain the Ruby code below, I can't able to understand the code.
In command_substitution.rb
a = %x!ps -def |grep bash!
puts a
Output
1000 3806 3799 0 10:54 pts/0 00:00:00 -bash
1000 4981 4979 0 12:50 pts/0 00:00:00 sh -c ps -def |grep bash
1000 4984 4981 0 12:50 pts/0 00:00:00 grep bash
I searched to find out what is command substitution using Google. But, I didn't get the exact explanation about it.
Please explain .
The %x notation is a literal for executing a shell script. Here, the character ! is used to indicate the start and the end of the literal. It runs the command ps -def |grep bash in the shell, assigns the result to variable a, and prints it.
Within the shell script, ps gets the running processes, | passes that to the next command, which is grep, which searches for the string bash within the processes shown.

Resources