count number of lines in terminal output - bash

couldn't find this on SO. I ran the following command in the terminal:
>> grep -Rl "curl" ./
and this displays the list of files where the keyword curl occurs. I want to count the number of files. First way I can think of, is to count the number of lines in the output that came in the terminal. How can I do that?

Pipe the result to wc using the -l (line count) switch:
grep -Rl "curl" ./ | wc -l

Putting the comment of EaterOfCode here as an answer.
grep itself also has the -c flag which just returns the count
So the command and output could look like this.
$ grep -Rl "curl" ./ -c
24
EDIT:
Although this answer might be shorter and thus might seem better than the accepted answer (that is using wc). I do not agree with this anymore. I feel like remembering that you can count lines by piping to wc -l is much more useful as you can use it with other programs than grep as well.

Piping to 'wc' could be better IF the last line ends with a newline (I know that in this case, it will)
However, if the last line does not end with a newline 'wc -l' gives back a false result.
For example:
$ echo "asd" | wc -l
Will return 1 and
$ echo -n "asd" | wc -l
Will return 0
So what I often use is grep <anything> -c
$ echo "asd" | grep "^.*$" -c
1
$ echo -n "asd" | grep "^.*$" -c
1
This is closer to reality than what wc -l will return.

"abcd4yyyy" | grep 4 -c gives the count as 1

Related

How to read the last executed command comment (after #) in bash?

I know there are some bash variables that are assigned after executing a Bash command. Some of them are $? to get the return value of the process or $BASH_COMMAND to get the actual call line, $1, $2 etc to retrieve the call args, etc.
A simple trick with trap would (taken from this question) allow me to store the last executed command:
alariva#trinsic:~/test$ trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
alariva#trinsic:~/test$ ls -l #I want to read this comment
total 0
-rw-rw-r-- 1 alariva alariva 0 Aug 23 01:30 readme.md
alariva#trinsic:~/test$ echo $previous_command
ls -l
alariva#trinsic:~/test$ echo $?
0
I need to get the comment that may come after the last command, but I'm not aware of any variable that would store it. Is there any way to read it?
I would like to get a similar behavior to this:
alariva#trinsic:~/test$ ls -l #I want this comment
readme.md
alariva#trinsic:~/test$ echo $BASH_COMMENT
I want this comment
alariva#trinsic:~/test$
Of course, the current situation is that I cannot retrieve any info from this:
alariva#trinsic:~/test$ echo $BASH_COMMENT
alariva#trinsic:~/test$
I'm also aware that comments may be completely stripped out after Bash interprets the call, so in that case I wonder if there exists a workaround (like a hook or something) to read it before it actually reaches bash.
So far, this is what I achieved:
alariva#trinsic:~/test$ ls -l #tosto
total 0
alariva#trinsic:~/test$ LAST=`fc -l | cut -c 6- | tail -n2 | head -n1`
alariva#trinsic:~/test$ echo "${LAST##*\#}"
tosto
alariva#trinsic:~/test$
Not sure if this is the best possible solution and if it'd work on all scenarios but looks like the behavior I want to achieve. Is there any built-in/alternative way to get this?
The closest solution I came up so far is the following.
alariva#trinsic:~/test$ ls -l #tosto
total 0
alariva#trinsic:~/test$ LAST=`fc -l | cut -c 6- | tail -n2 | head -n1`
alariva#trinsic:~/test$ echo "${LAST##*\#}"
tosto
alariva#trinsic:~/test$
While that will work for most of the scenarios I use, it still will fail to get the full comment on some scenarios where more than one # is found:
alariva#trinsic:~/test$ ls -l #tosto #only partial
total 0
alariva#trinsic:~/test$ LAST=`fc -l | cut -c 6- | tail -n2 | head -n1`
alariva#trinsic:~/test$ echo "${LAST##*\#}"
only partial
alariva#trinsic:~/test$
Improvements on this answer are welcome.

bash: differing newline count when assigning result to variable [duplicate]

This question already has answers here:
Check number of running scripts using ps
(4 answers)
Closed 6 years ago.
let's say I want to see how many copies of a program are already running. I could do something like this:
ps ax | grep -c "$0"
that command by itself produces the expected result. BUT if I attempt to assign the output to a variable, it gets incremented by one! No matter how I try it:
var=$(ps ax | grep "$0" | sed -n '$=')
var=`ps ax | grep -c "$0"`
can someone please show me the right way to capture the correct output?
it would also be great to know why this is happening..
UPDATE
after the first response from #fedorqui I realize I wasn't clear enough. let me elaborate:
I am running all three commands above in the same bash script. When I run the first one, it prints out the number 2: the program itself and the grep process with that program as an argument. when I run those same commands within variable assignments, the number 3 is stored.
please note that I am using two different methods of counting lines, grep and sed. in both cases they return 3 instead of the correct answer, 2.
here is a consolidated example to try in a test.sh file:
echo -n "without assignment: "
ps ax | grep -c "$0"
var=$(ps ax | grep "$0" | sed -n '$=')
echo "using sed method: $var"
var=`ps ax | grep -c "$0"`
echo "using grep method: $var"
the results on my debian box:
without assignment: 2
using sed method: 3
using grep method: 3
the questions again: why is this happening, and how to prevent or work around?
Quoting Siegex:
Because the grep process itself is being returned by ps.
You can either of these:
"trick" grep to not match itself by surrounding one of the search
characters in a character class [ ] which doesn't change the
functionality:
Or, in this case,
Pipe to grep -v grep, so that the process doesn't match:
var=$(ps ax | grep -v grep | grep "$0")
See an example. Here we have a process sleep:
$ sleep 20 &
[1] 5602
If we check for it in the output of ps it appears twice!
$ ps -ef| grep sleep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
me 5607 5433 0 09:49 pts/2 00:00:00 grep --colour=auto sleep
So we can either use a character class:
$ ps -ef| grep [s]leep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
Or grep out the grep process:
$ ps -ef| grep sleep | grep -v grep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
Command substitution itself runs in a subshell so thats one bash process
your search for bash ($0) i.e. grep -c bash also ends up in the process table at that time so thats another process (grep) containing string bash. Note that, this might not show up in the process table at the time of running, depending on how busy your system is.
And you have two (or whatever) actual bash processes (sessions) running presumably are the rest
You can use a Regex trick to get rid of the false positive i.e. grep one from count:
ps ax | grep -c "[b]ash"
It would still count the subshell while doing command substitution:
var=$(ps ax | grep -c "[b]ash")
So you need to manually remove one from this count.
Example:
$ var=$(ps ax | grep -c "bash")
$ echo $var
4
$ var=$(ps ax | grep -c "[b]ash")
$ echo $var
3
Your command counts the grep command line too.
ps ax | grep -v grep | grep -c "$0"
should omit the grep from the count

Pass contents of LaTeX statement to command

I can extract the contents of all the \include statements from a latex file (and append ".tex" to each one) with
grep -P "\\\\include{" Thesis_master.tex |sed -n -e"s/\\\\include{/$1/" -e" s/}.*$/.tex/p"
(I couldn't get lookbehinds working in grep, hence the pipe through sed. That gives me a list of filenames, one per line. I'd now like to pass those files to aspell. But aspell only accepts one filename as an argument, so I can't just tack |xargs aspell -c on the end.
I've read this related question but that reads from a file line by line through xargs. So how do I get it to read from the output of sed line by line?
I think xargs -L 1 should do what you need:
grep -P "\\\\include{" Thesis_master.tex | \
sed -n -e"s/\\\\include{/$1/" -e" s/}.*$/.tex/p" | \
xargs -L 1 aspell -c
(Backslash line continuation added for readability)
This will cause xargs to call aspell exactly once per line from the sed pipe.
Since your aspell commands appear to exit with a 255 code, this causes xargs to stop. You could trick xargs into not exiting by doing something like:
grep -P "\\\\include{" Thesis_master.tex | \
sed -n -e"s/\\\\include{/$1/" -e" s/}.*$/.tex/p" | \
xargs -L 1 -I % bash -c "aspell -c %; true"
This will run aspell in a subshell, followed by the true command which always return a 0 exit code to xargs.
The grep recipe is:
grep -oP '\\include{\K.+?(?=})' latex.file | xargs aspell ...

simple bash script not terminating

I have very simple bash script:
#!/bin/bash
echo -n "A: ";
grep -v ">" | grep -o "A" $1 | wc -l;
I type
./script.sh 1.fasta
I got
A: 131
But the curcor is still blicking and my script is not finishing. What's wrong here?
Thank you.
This is the problem command:
grep -v ">" | grep -o "A" $1 | wc -l;
Since first command grep -v ">" is waiting for the input from STDIN as you haven't supplied any file to be searched by grep.
PS: Even grep -o "A" $1 is also problem since piped command will take input from output of the previous command in chain.
Probably you meant:
grep -v ">" "$1" | grep -o "A" | wc -l
Your first grep does not have a file argument so it will read from standard input:
grep -v ">" | grep -o "A" $1 | wc -l;
(read stdin) (read $1)
The reason why you get the 131 is because your second grep does have a file argument so it's getting all lines in $1 that have an A. However it's still waiting around for the end of the first grep to finish (which you can do with CTRL-D).
What you probably wanted to do is this:
grep -v ">" "$1" | grep -o "A" | wc -l
This will find all lines in $1 without a >, then all occurrences of A in that, counting them.

bash output redirect prob

I want to count the number of lines output from a command in a bash script. i.e.
COUNT=ls | wc -l
But I also want the script to output the original output from ls. How to get this done? (My actual command is not ls and it has side effects. So I can't run it twice.)
The tee(1) utility may be helpful:
$ ls | tee /dev/tty | wc -l
CHANGES
qpi.doc
qpi.lib
qpi.s
4
info coreutils "tee invocation" includes this following example, which might be more instructive of tee(1)'s power:
wget -O - http://example.com/dvd.iso \
| tee >(sha1sum > dvd.sha1) \
>(md5sum > dvd.md5) \
> dvd.iso
That downloads the file once, sends output through two child processes (as started via bash(1) process substitution) and also tee(1)'s stdout, which is redirected to a file.
ls | tee tmpfile | first command
cat tmpfile | second command
Tee is a good way to do that, but you can make something simpler:
ls > __tmpfile
cat __tmpfile | wc -l
cat __tmpfile
rm __tmpfile

Resources