Shell exec command with | fails - shell

I write a script with | in command , it run fail .
#! /bin/bash
datestr=`date -d '-1 day' '+%Y-%m-%d'`
cmd="cat /service/domain_detect/api/storage/logs/laravel.log | grep sub_domain | grep $datestr | wc -l"
echo $cmd
count=$($cmd)
echo $count
Expected output is the result line num.
The actual result is follow:
cat /service/domain_detect/api/storage/logs/laravel.log | grep sub_domain | grep 2019-01-17 | wc -l
cat: invalid option -- 'l'
Try 'cat --help' for more information.

Related

ps -ef | grep * command not working properly

I have simple unix shell script as follows. Which is giving different count for a service
#!/bin/bash
service=$1
ps -ef | grep $service | grep -v "grep" | wc -l
PROCESS_NUM=$(ps -ef | grep $service | grep -v "grep"| wc -l)
echo $PROCESS_NUM
In the above code below line gives output of 2.
ps -ef | grep $service | grep -v "grep" | wc -l
But when same line is assigned to variable as code below its giving output as 3.
PROCESS_NUM=$(ps -ef | grep $service | grep -v "grep"| wc -l)
echo $PROCESS_NUM
Why this is getting increased by 1 and how to tackle it.
You can see what is happening if the script tees the output to a file before counting the lines and then displaying the output after:
#!/bin/bash
service=$1
echo Directly in Script:
ps -ef | grep $service | grep -v grep | tee test.txt | wc -l
cat test.txt
echo Inside Subshell:
RESULT=$(ps -ef | grep $service | grep -v grep | tee test.txt | wc -l)
echo $RESULT
cat test.txt
When the output of a command is captured, bash starts another shell to run the command - but that subshell also shows up in the process list.
When I run that script I get:
$ ./test.sh lca
Directly in Script:
2
gcti 4268 1 0 2018 ? 21:59:03 ./lca 4999
t816826 9159 7009 0 09:22 pts/1 00:00:00 /bin/bash ./test.sh lca
Inside Subshell:
3
gcti 4268 1 0 2018 ? 21:59:03 ./lca 4999
t816826 9159 7009 0 09:22 pts/1 00:00:00 /bin/bash ./test.sh lca
t816826 9166 9159 0 09:22 pts/1 00:00:00 /bin/bash ./test.sh lca

bash fork subprocess with command link $(cmd1|cmd2)

Question
I wrote some command lines like output=$(cmd1|cmd2) in a bash script file (aaaa.sh) and found a subprocess generated.
code in the file aaaa.sh
echo "The name of this file is $(basename $0)."
echo "The pid of this program is $$."
echo -e '\n---- 0 ----'
echo -e 'CMD: ps -ef | grep "aaaa.sh" | grep -v grep'
ps -ef | grep "aaaa.sh" | grep -v grep
echo -e '\n---- 1 ----'
echo -e 'CMD: ps -ef | grep "aaaa.sh" | grep -v "bbbb" | grep -v grep'
ps -ef | grep "aaaa.sh" | grep -v "bbbb" | grep -v grep
echo -e '\n---- 2 ----'
echo -e 'CMD: pgrep -a "aaaa.sh" | grep -v "bbbb"'
pgrep -a "aaaa.sh" | grep -v "bbbb"
echo -e '\n---- 3 ----'
echo -e 'CMD: pgrep -a "aaaa.sh" | grep -v "$$"'
pgrep -a "aaaa.sh" | grep -v "$$"
echo -e '\n---- 4 ----'
echo -e 'CMD: output=$(ps -ef | grep "aaaa.sh" | grep -v "bbbb" | grep -v grep)'
output=$(ps -ef | grep "aaaa.sh" | grep -v "bbbb" | grep -v grep)
echo -e "$output"
echo -e '\n---- 5 ----'
echo -e 'CMD: output=$(ps -ef | grep "aaaa.sh" | grep -v "$$" | grep -v grep)'
output=$(ps -ef | grep "aaaa.sh" | grep -v "$$" | grep -v grep)
echo -e "$output"
echo -e '\n---- 6 ----'
echo -e 'CMD: output=$(pgrep -a "aaaa.sh" | grep -v "bbbb")'
output=$(pgrep -a "aaaa.sh" | grep -v "bbbb")
echo -e "$output"
echo -e '\n---- 7 ----'
echo -e 'CMD: output=$(pgrep -a "aaaa.sh" | grep -v "$$")'
output=$(pgrep -a "aaaa.sh" | grep -v "$$")
echo -e "$output"
echo -e '\n---- 8 ----'
echo -e 'CMD: output=$(pgrep -a "aaaa.sh")'
output=$(pgrep -a "aaaa.sh")
echo -e "$output"
output
output
Question
There is a subprocess generated in 4,5,6 and 7. why?
Shells typically execute command substitution ($()) and command piping (|) in subshells.
output=$(ps -ef | grep "aaaa.sh" | grep -v "$$" | grep -v grep)
This statement actually results in the creation of five processes--one for the command substitution subshell, and one more for each of the commands in the pipeline.
From the bash man page:
Each command in a pipeline is executed as a separate process (i.e., in a subshell).
Edit - To try this out for yourself run the following:
$ echo $BASHPID >&2 | echo $BASHPID >&2 | echo $BASHPID
We can see a different PID for each subshell in the pipeline.
That's probably because of
$(...)
Quote from bash man page:
Command substitution allows the output of a command to replace the command name. There are two forms:
$(command)
or
`command`.
Bash performs the expansion by executing command in a subshell environment and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during
word splitting.
So, you actually see the subshell created to execute your commands

expression using grep is giving all zeros

So I have an expression that I want to extract some lines from a text and count them. I can grep them as follows:
$ cat medsCounts_totals.csv | grep -E 'NumMeds": 0' | wc -l
Which is fine. Now I want to loop over with the string ...
$ for i in {0..10}; do expr="NumMeds\": $i"; echo $expr; done
However, when I try to use $expr
for i in {0..10}; do expr="NumMeds:\" $i"; cat medsCounts_totals.csv | grep -E "$expr" | wc -l ; done
I get nothing. How do I solve this problem in an elegant manner?
there is a typo in
for i in {0..10}; do expr="NumMeds:\" $i"; cat medsCounts_totals.csv | grep -E "$expr" | wc -l ; done
it should be
"NumMeds\": $i"

BASH: Remove newline for multiple commands

I need some help . I want the result will be
UP:N%:N%
but the current result is
UP:N%
:N%
this is the code.
#!/bin/bash
UP=$(pgrep mysql | wc -l);
if [ "$UP" -ne 1 ];
then
echo -n "DOWN"
else
echo -n "UP:"
fi
df -hl | grep 'sda1' | awk ' {percent+=$5;} END{print percent"%"}'| column -t && echo -n ":"
top -bn2 | grep "Cpu(s)" | \sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | \awk 'END{print 100 - $1"%"}'
You can use command substitution in your first sentence (notice you're creating a subshell in this way):
echo -n $(df -hl | grep 'sda1' | awk ' {percent+=$5;} END{print percent"%"}'| column -t ):

How to store the output of sed command in shell script

past_date=`date +"%Y-%m-%d" -d "-60 day"`
initial_date= sed -n "/$past_date/p" 'logfile.txt' | head -1 | sed -e 's/\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\).*/\1/'
echo $initial_date
/*I am trying to store the result of sed command to initial_date variable. But nothing is stored in initial_date*/
To store a command output into a variable $var, use the var=$(command) syntax:
initial_date=$(sed -n "/$past_date/p" 'logfile.txt' | head -1 | sed -e 's/\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\).*/\1/')
Then to print the result it is always recommended to quote the variable:
echo "$initial_date"
Update
If you are looking for the first date hour in logfile.txt, being date the $past_date, then you can use:
grep -o -m1 '2013-11-14 [0-9][0-9]:[0-9][0-9]:[0-9][0-9]' logfile.txt
Given this sample file:
$ cat logfile.txt
hello 2013-11-14 11:12:33
2013-11-14 11:12:33
2013-21-14 11:12:33
2013-r2:33
2013-19-14
2013-11-10 adf
$ grep -o -m1 '2013-11-14 [0-9][0-9]:[0-9][0-9]:[0-9][0-9]' logfile.txt
2013-11-14 11:12:33
$ data=$(grep -o -m1 '2013-11-14 [0-9][0-9]:[0-9][0-9]:[0-9][0-9]' logfile.txt)
$ echo $data
2013-11-14 11:12:33
initial_time=echo $line | sed -e 's/\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\).*/\1/'

Resources