How to grep the pidof bash in a shell script? [closed] - bash

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I want to get the PID of bash and highlight it if it's in some textfile (assume it is). So when I'm typing this in my shell:
grep -o $(pidof bash) test.txt
it just works fine and gives me the desired output, the PID of bash.
Then why is this script not working:
#!/bin/bash
PID=$(grep -o $(pidof bash) test.txt)
echo $PID
I only get some lines with:
grep: xxx: file or directory not found
xxx are random numbers, but usually the last one is the one I'm looking for.
How do I achieve this and why is the above not working?
Has this something to do with creating a new process by the shell when calling grep in the script?
Thank you.

I don't have pidof, so I'm assuming that it's an equivalent to pgrep -v, printing a list of PIDs, one on each line, with a newline between them.
If that's so, consider this:
egrep -o "$(pgrep -v bash | tr '\n' '|')" test.txt
Assume that the output of pgrep -v bash is:
123
456
789
Your original code would do this:
egrep -o 123 456 789 test.txt
...thus, searching for 123 in a file named 456, in a file named 789, and in a file named test.txt.
Now, compare to what happens when you replace that whitespace with pipe symbols:
egrep -o "123|456|789" test.txt
...as executed by the pipeline suggested earlier in this question is exactly what you were looking for. (BTW, the quotes here are purely syntactic -- that is, they're for consumption by the shell when it's understanding how things are parsed, not passed to egrep).
That said, if you're looking for the current bash process, use either $$ (for the parent PID of the current shell) or $BASH_PID (for the current shell itself even if it's a subshell), rather than using so inexact a tool as pgrep or pidof.

When you run pidof inside your shell script, there are at least two instances of bash running, so it will return multiple numbers. The way grep is designed, it can only search for one pattern at a time so the first number is interpreted as a pattern and the other numbers are mistakenly interpreted as file or directory names.
I'm not sure which bash PID you care about, but one solution is to use something like grep, head, or tail to filter the output of pidof so you just get one number. Another solution is to use the special variable $$, which is the PID of bash instance that evaluates it.
In the future, you can debug this better for yourself. To debug, I would start by running this command inside your script to see exactly what arguments are being passed to grep:
echo grep -o $(pidof bash) test.txt

Related

Redirection vs Piping [duplicate]

This question already has answers here:
Useless use of cat?
(9 answers)
Piping and Redirection
(5 answers)
Closed 3 years ago.
What is the difference between the statement cat a.txt | wc and the statement wc < cat a.txt. In both cases, isn’t the output of cat a.txt being directed into wc?
Absolutely not. In your second case (wc < cat a.txt) you are invoking the command wc a.txt while connecting a file named cat to the standard input of the process.
It might seem confusing, but most shells allow you to redirect the input anywhere in the command line.
wc a.txt < cat
would be the same as (the arguably more confusing)
wc < cat a.txt
To redirect the output of a command to the input of another, you use the pipe character. To invoke a command with a file as its standard input, you use the chevrons.
Now, modern shells will let you type commands like this one:
wc <(cat a.txt)
This is called process substitution and is not exactly the same thing as either of the two methods you were asking about. In this case, the shell will invoke the process cat a.txt and "catch" its output in a file descriptor. Then, the shell will invoke the "main" command (wc) and pass a reference to that file descriptor as an argument, as if it were a file name. It enables a command that expects a simple file name to read the output of an ad hoc command.

Unix shell programming to count number of active user using Korn shell

What is the shell script to count number of logged in user who are using Korn shell currently using grep and any other Unix command. Thanks in advance.
who is a command that lists users who are online. In order to count the number of online users, you can pipe the output of who to grep, which can count the number of lines with the -c argument:
who | grep -c .
EDIT: I missed the detail about users using Korn shell.
You can try this instead:
ps -e -o command | grep -c "[k]sh"
ps is a command that lists information about current running processes. The -e argument makes it show information about all system processes and the -o command arguments makes it shows only commands.
ps -e -o command will show you a list of currently running processes. Now, you can pipe the output to grep and count the number of lines that match [k]sh using the -c argument. Brackets are used around the "k" because otherwise grep will match itself, as the grep command contains "ksh" as an argument. (You can see this by checking the output of ps -e -o command.)
(I am assuming that the name of the Korn shell process is "ksh". If it is something else, you should using that as the argument for grep.)

Procmail - passing body to bash script

I have one liner mails that I wish to send from procmail into a bash script. I only want the body to be sent, nothing else.
Currently my .procmailrc looks like this:
:0
*^ Subject.*Xecute Command$
{
:0 bf
| /bin/bash /path/to/script
}
And my Bash script is simple:
#!/bin/bash
echo -e "\rLT 4>$0\r\r" > /dev/ttyS1
I don't get any input or output from anywhere.
Any pointers?
If the intention is to add some decorations to the email message and print it to a serial port (?), try a recipe like
:0b
*^ Subject.*Xecute Command$
| ( printf '\rLT 4>'; cat -; printf '\r\r' ) > /dev/ttyS1
The b flag applies to the action line if the condition matches, so you don't need the braces and a new conditionless recipe; the f flag makes no sense at all in this context. (Though if you want to keep the message for further processing, you'll want to add a c flag.)
Also, for the record, $0 in Bash is the name of the currently running script (or bash itself, if not running a script), and $# is the list of command-line arguments. But Procmail doesn't use either of these when it pipes a message to a script; it is simply being made available on standard input.
If you want the action in an external script, that's fine, too, of course; but a simple action like this is probably better written inline. You don't want or need to specify bash explicitly if the script file is executable and has a proper shebang; the reason to have a shebang is to make the script self-contained.
In response to comments, here is a simple Perl script to extract the first line of the first body part, and perform substitutions.
perl -nle 'next if 1../^$/;
s/\<foo\>/bar/g;
print "\rLT 4>$_\r\r"; exit(0)'
This would not be hard to do in sed either, provided your sed understands \r.
Write your script like that:
{
echo -e "\rLT 4>"
cat
echo -e "\r\r"
} > /dev/ttyS1
formail is your friend!
Pipe the message into:
:0
*^ Subject.*Xecute Command$
| formail -I "" | your-bash-script

beginner's bash script with parameters to be fed to the commands in the script

I want to make a bash script which invokes some simple commands in the following way
./myscript magicword
would invoke
#!/bin/bash
cat * | grep "$#"
However I want to add one more level of complexity, for example triggering case sensitivity or not. Thus I want to include he parsing of arguments such as
./myscript --case-insensitive magicword
which should be interpreted by the script as grep -i "$#".
I have seen many tutorials about bash scripting with arguments, and case structures, but those had to do mostly with each executing different commands altogether, or assigning variables (which are not actually using them as command options).
I didn't find a way of a syntax such as grep $1 "$#" or something, where $1 ought to be null, or anything else.

How can you pipe the output of a script that has ${1+"$#"} variables used within it?

There are a bunch of scripts that I would like to run and grep the output. For example, running this works and has the desired output lines:
$ myScript.sh
Running this does not:
$ myScript.sh | grep something
After further review, myScript.sh has this in it:
#!/bin/sh
...
$JAVA_HOME/bin/java the.real.script.is.here ${1+"$#"}
I am assuming that the " | grep something" gets sucked into the $# list. Any ideas on how I can pipe the output easily? Thanks!
EDIT: Thanks everyone for the info about how variables are parsed. It must be something else that is the problem. Maybe it is what I am grepping for. In my output I am looking for lines with "/SE_2012.old". I ran the script again with "|grep old" and got no output. I ran it with "| grep SE", and got a result. I ran it again with "old" to see if I was going crazy, and it DID give me a result.
First of all, your assumption is incorrect. The shell parses its command line well enough to tell the difference between a pipe and an argument. That's why you need quotes in order to escape redirects, pipes, subshells, and other low-level expressions.
Now, to the problem at hand: Assuming you don't see any output when you run
$ myScript.sh | grep something
you're probably seeing the effect of buffering*. Unfortunately, I can't tell you exactly how it's happening in the java application, so I can't give you a direct solution to it, but perhaps if you examine the internals of the java code you can tell.
* As opposed to the output just going someplace other than standard output.
It's impossible for "| grep something" to be sucked into the $# list, so there should be another problem. Maybe the script uses line buffering for tty output, and full buffering otherwise? (Do you wait for script completion before concluding it doesn't work?) Maybe "something" in "grep something" gets interpreted (unexpectedly) as regular expression that doesn't match input lines?
Try cat instead of grep something: does it work?
Show us the real value of "something".

Resources