"/bin/grep: Unmatched [ or [^" in bash loop - bash

I am trying to write a Bash alias (or script) which lists which of some particular programs are currently running.
In my .bashrc I have set $MY_BIN_PATH to a directory containing all the programs of interest to me:
export MY_BIN_PATH=/root/repo/bin
$ > echo $MY_BIN_PATH
/root/repo/bin
Listing that directory shows a number of files. I want to grep the output of ps -ef for each of these:
for i in `ls $MY_BIN_PATH`;
do
ps -ef | grep $i | egrep -v "grep|md_m|avahi";
done
Regardless of which (if any) of the files in $MY_BIN_PATH are running, the output is always:
/bin/grep: Unmatched [ or [^
/bin/grep: Unmatched [ or [^
/bin/grep: Unmatched [ or [^
/bin/grep: Unmatched [ or [^
/bin/grep: Unmatched [ or [^
It seems like somehow the value of $i is "forgotten" in the pipe between ps -ef and grep $i.
What am I doing wrong here, and how can I make it work?

First, check if ls is aliased to something. Maybe you should use the absolute path to ls and without any options. Make sure it is not system-aliased to color-ls or something.
Second, you can change the loop header to
for i in $MY_BIN_PATH/*
and that may fix it as well.

As a start, never parse the output of ls
Secondly, parameters needs to be properly quoted
Try this:
for i in $MY_BIN_PATH/*
do
ps -ef | grep "$i" | egrep -v "grep|md_m|avahi"
done
To get the PID of a running process when you know the process name, use pidof().
What are you trying to achive with the loop in the end?

Related

2 tail -f with different command

I'm trying to make a shell script to monitor a log file, but I have a problem which is I can't do two tail at the same time.
the script basically is to search for a word if it matches it will redirect the 3 lines include the matched word into a file then I will pruning the useless information to extract what I want.
I tried the commands below and it's working fine but when I mirage it in a file it doesn't work
please advise :)
below is a part of the script,
#!/bin/bash
#grep error log
tail -f /FileLogging.log | grep 'error' >>/home/hello/tech.txt
#pruning useless information
tail -f /home/hello/tech.txt perl -nle "print $1 if /sam-(.+?)\",\"jack/" >>/home/hello/non.txt
Now I detected, the there only one source is watched. So this command should combine both of your example:
tail -f /FileLogging.log | grep 'error' | tee -a /home/hello/tech.txt | perl ... >>/home/hello/non.txt

bash command substitution's result not consistent

I have a script.
cat /root/test/ddd.sh
#!/bin/bash
s=/root/test/ddd.sh
ps -ef | grep $s | grep -v grep
result=$(ps -ef | grep $s | grep -v grep | wc -l)
echo $result
when i execute it, the result is weird, it shows that there is two line matched.
[root#l2 test]# /root/test/ddd.sh
root 15361 15032 0 09:52 pts/18 00:00:00 /bin/bash /root/test/ddd.sh
2
That's because you're running a subshell. That is, the $(...) piece causes bash to fork, thereby creating two (nearly) identical processes. By identical, I mean basically everything except for process ID, parent process ID, return code from the fork, and I can't think of anything else. But one thing that does remain the same for sure is the command line. Both of them will be "/bin/bash /root/test/ddd.sh". So, inside the result=$(...), there will be exactly one extra process that matches.
You can see this, for example, by removing the | wc -l piece at the end of your $(...), and, to make it more readable, enclose the echo's argument in quotes:
result="$(ps -ef | grep $s | grep -v grep)"
echo "$result"
Here you will see that there are two bashes, and the PPID of one is the PID of the other, showing the parent-child relationship.

bash: pipe continuously into a grep

Not sure how to explain this but, what I am trying to achieve is this:
- tailing a file and grepping for a patter A
- then I want to pipe into another customGrepFunction where it matches pattern B, and if B matches echo something out. Need the customGrepFunction in order to do some other custom stuff.
The sticky part here is how to make the grepCustomFunction work here.In other words when only patternA matches echo the whole line and when both patterA & patternB match printout something custom:
when I only run:
tail -f file.log | grep patternA
I can see the pattenA rows are being printed/tailed however when I add the customGrepFunction nothing happens.
tail -f file.log | grep patternA | customGrepFunction
And the customGrepFunction should be available globally in my bin folder:
customGrepFunction(){
if grep patternB
then
echo "True"
fi
}
I have this setup however it doesn't do what I need it to do, it only echos True whenever I do Ctrl+C and exit the tailing.
What am I missing here?
Thanks
What's Going Wrong
The code: if grep patternB; then echo "true"; fi
...waits for grep patternB to exit, which will happen only when the input from tail -f file.log | grep patternA hits EOF. Since tail -f waits for new content forever, there will never be an EOF, so your if statement will never complete.
How To Fix It
Don't use grep on the inside of your function. Instead, process content line-by-line and use bash's native regex support:
customGrepFunction() {
while IFS= read -r line; do
if [[ $line =~ patternB ]]; then
echo "True"
fi
done
}
Next, make sure that grep isn't buffering content (if it were, then it would be written to your code only in big chunks, delaying until such a chunk is available). The means to do this varies by implementation, but with GNU grep, it would look like:
tail -f file.log | grep --line-buffered patternA | customGrepFunction

How can I use grep as cat

I am creating a script that parses some files and greps out the necessary information.
I have set up many different variables in arrays that search for different aspects in the files.
e.g. dates, locations, types.
However I wanted to make each of these variables optional which is where I run into an issue.
the syntax of the command would have been simple
grep ${dates} filename | grep ${locations} | grep ${types}
However, due to variables being optional, the above won't work if a variable is unset.
I was trying to find a way to get grep to find anything (i.e. like egrep .* filename)
that way I could set the variables to the proper regex and have the command still run.
unfortunately, when I set the variable to equal '' it freezes, when I set it to '.' it just greps everything from every file in the current directory and when I leave the variable blank it takes the filename as the variable and waits for a filename.
is there anyway that I can set a variable so that grep $variable file outputs the same as cat would?
Many thanks in advance!
To get grep to act like cat use an empty string as a search pattern, i.e. grep "". Therefore to make some of those variables optional, but not have piped greps fail, just quote the variables:
grep "${dates}" filename | grep "${locations}" | grep "${types}"
Demonstration. Search {250,255,260...280} for the digits 5, 2, and 7:
x=5 y=2 z=7 ; seq 250 5 280 | grep "$x" | grep "$y" | grep "$z"
275
Now unset two of the variables, and it still works:
unset x y ; seq 250 5 280 | grep "$x" | grep "$y" | grep "$z"
270
275
If there aren't any $dates in filename then there is nothing to feed the rest of the pipeline.
I think the best way to do it is to grep for each string separately.
If you get a match, then grep for the next string.
Can you post the source file and a target output. From your question it sounds like you just need to use grep -E in conjunction with the | pipe delimiter.
grep -E "${dates}|${locations}|${types}" fileName
The above line should automatically get you every occurrence of the any of the patterns. This is not even a regex yet.

How can grep interpret literally a string that contains an asterisk and is fed to grep through a variable?

I have this script:
#!/bin/bash
CLASSPATH="/blah/libs/*:/blah/more/libs"
CMD="java -cp $CLASSPATH MainClass"
ALREADY_RUNNING_PID=`ps -ef --no-headers | grep $CMD | grep -v grep | awk '{print $2}'`
if [ "$ALREADY_RUNNING_PID" ]; then
echo "Already running"
exit 1
fi
$CMD &
problem is it doesnt work due to the asterisk in the CMD variable. how can i tell grep to see the variable value as it is? Any solution? It is mandatory that grep is fed through the variable.
Thanks.
Since you are not using regular expressions you can use fgrep $CMD instead of grep
The problem is not grep, it's
CLASSPATH="/blah/libs/*:/blah/more/libs"
If you do
echo $CLASSPATH
you should see that your shell has expanded the * to all files in that directory. To remedy this, just use single quotes to prevent globbing:
CLASSPATH='/blah/libs/*:/blah/more/libs'
Totally unrelated to your specific grep problem, but jps will report on running Java processes and possibly make your grepping easier since you'd most likely have to just do:
jps | grep MainClass
(or something similar)

Resources