Better shell solution when blank lines may be piped to wc
Clash Royale CLAN TAG#URR8PPP
up vote
1
down vote
favorite
I have code that does something like this:
#!/bin/sh
CONTENTS=$(cat "somefile")
RELEVANT_LINES=$(echo "$CONTENTS" | grep -E "SEARCHEXPR")
COUNT=$(echo "$RELEVANT_LINES" | wc -l)
I hit an annoyance that this code didn't output the same if there weren't any matches, compared to the correct output given by replacing the third line with :
COUNT=$(echo "$CONTENTS" | grep -E "SEARCHEXPR" | wc -l)
I eventually traced to the fact that when there weren't any matches, RELEVANT_LINES was being set to the empty string, and echo was outputting a one line empty string + n for a line count of 1.
I tried using printf and echo -n in the 3rd line, but couldn't find the elegant workaround and ended up using COUNT=$(echo "$RELEVANT_LINES" | grep '0' | wc -l)
(all lines contain a zero) to avoid having to regex filter the entire source file twice.
That can't be right, but I can't figure the correct fix.
I didn't drop to scripting with -eq ''
because I wasn't sure it would be as robust and I prefer piping directly to wc
for pure neatness.
Any hints how to get file content in a variable, to neatly distinguish zero vs one line after being filtered by grep? :)
shell-script shell newlines
add a comment |Â
up vote
1
down vote
favorite
I have code that does something like this:
#!/bin/sh
CONTENTS=$(cat "somefile")
RELEVANT_LINES=$(echo "$CONTENTS" | grep -E "SEARCHEXPR")
COUNT=$(echo "$RELEVANT_LINES" | wc -l)
I hit an annoyance that this code didn't output the same if there weren't any matches, compared to the correct output given by replacing the third line with :
COUNT=$(echo "$CONTENTS" | grep -E "SEARCHEXPR" | wc -l)
I eventually traced to the fact that when there weren't any matches, RELEVANT_LINES was being set to the empty string, and echo was outputting a one line empty string + n for a line count of 1.
I tried using printf and echo -n in the 3rd line, but couldn't find the elegant workaround and ended up using COUNT=$(echo "$RELEVANT_LINES" | grep '0' | wc -l)
(all lines contain a zero) to avoid having to regex filter the entire source file twice.
That can't be right, but I can't figure the correct fix.
I didn't drop to scripting with -eq ''
because I wasn't sure it would be as robust and I prefer piping directly to wc
for pure neatness.
Any hints how to get file content in a variable, to neatly distinguish zero vs one line after being filtered by grep? :)
shell-script shell newlines
1
Can't the whole thing be replaced byCOUNT=$(grep -Ec "SEARCHEXPR" somefile)
?
â steeldriver
Jan 14 at 13:36
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have code that does something like this:
#!/bin/sh
CONTENTS=$(cat "somefile")
RELEVANT_LINES=$(echo "$CONTENTS" | grep -E "SEARCHEXPR")
COUNT=$(echo "$RELEVANT_LINES" | wc -l)
I hit an annoyance that this code didn't output the same if there weren't any matches, compared to the correct output given by replacing the third line with :
COUNT=$(echo "$CONTENTS" | grep -E "SEARCHEXPR" | wc -l)
I eventually traced to the fact that when there weren't any matches, RELEVANT_LINES was being set to the empty string, and echo was outputting a one line empty string + n for a line count of 1.
I tried using printf and echo -n in the 3rd line, but couldn't find the elegant workaround and ended up using COUNT=$(echo "$RELEVANT_LINES" | grep '0' | wc -l)
(all lines contain a zero) to avoid having to regex filter the entire source file twice.
That can't be right, but I can't figure the correct fix.
I didn't drop to scripting with -eq ''
because I wasn't sure it would be as robust and I prefer piping directly to wc
for pure neatness.
Any hints how to get file content in a variable, to neatly distinguish zero vs one line after being filtered by grep? :)
shell-script shell newlines
I have code that does something like this:
#!/bin/sh
CONTENTS=$(cat "somefile")
RELEVANT_LINES=$(echo "$CONTENTS" | grep -E "SEARCHEXPR")
COUNT=$(echo "$RELEVANT_LINES" | wc -l)
I hit an annoyance that this code didn't output the same if there weren't any matches, compared to the correct output given by replacing the third line with :
COUNT=$(echo "$CONTENTS" | grep -E "SEARCHEXPR" | wc -l)
I eventually traced to the fact that when there weren't any matches, RELEVANT_LINES was being set to the empty string, and echo was outputting a one line empty string + n for a line count of 1.
I tried using printf and echo -n in the 3rd line, but couldn't find the elegant workaround and ended up using COUNT=$(echo "$RELEVANT_LINES" | grep '0' | wc -l)
(all lines contain a zero) to avoid having to regex filter the entire source file twice.
That can't be right, but I can't figure the correct fix.
I didn't drop to scripting with -eq ''
because I wasn't sure it would be as robust and I prefer piping directly to wc
for pure neatness.
Any hints how to get file content in a variable, to neatly distinguish zero vs one line after being filtered by grep? :)
shell-script shell newlines
asked Jan 14 at 13:25
Stilez
436211
436211
1
Can't the whole thing be replaced byCOUNT=$(grep -Ec "SEARCHEXPR" somefile)
?
â steeldriver
Jan 14 at 13:36
add a comment |Â
1
Can't the whole thing be replaced byCOUNT=$(grep -Ec "SEARCHEXPR" somefile)
?
â steeldriver
Jan 14 at 13:36
1
1
Can't the whole thing be replaced by
COUNT=$(grep -Ec "SEARCHEXPR" somefile)
?â steeldriver
Jan 14 at 13:36
Can't the whole thing be replaced by
COUNT=$(grep -Ec "SEARCHEXPR" somefile)
?â steeldriver
Jan 14 at 13:36
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
4
down vote
Using CONTENTS
to hold the file just to echo
it again is a bit redundant, you could just
lines=$(cat "somefile" | grep -E "SEARCHEXPR")
or rather
lines=$(grep -E "SEARCHEXPR" "somefile")
If you just want the count of matching lines, use grep -c
count=$(grep -c -E "SEARCHEXPR" "somefile")
The immediate issue you see is caused by the fact that echo
outputs the newline always. In the case where you get at least one line from the command substitutions, this actually helps, since command substitutions remove trailing newlines. It also works with tailing empty lines, try this to see: x=$(echo foo; echo; echo); echo "$x"
.
If you want to process the lines in the shell script in some other way, in addition to counting, then storing the text in a variable might not be best. You could try
for line in $lines ; do
something with "$line"
done
But that has the usual issues with unquoted variables, i.e. filename globbing and word splitting on whitespace. One line containing "foo bar doo", would be seen as three, since by default, the spaces split too.
You might want to use a while read
loop instead, but for that, a shell that supports process substitution might be good to have. See BashFAQ 001 and variable doesn't change after find & while and in bash, read after a pipe is not setting values .
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
Using CONTENTS
to hold the file just to echo
it again is a bit redundant, you could just
lines=$(cat "somefile" | grep -E "SEARCHEXPR")
or rather
lines=$(grep -E "SEARCHEXPR" "somefile")
If you just want the count of matching lines, use grep -c
count=$(grep -c -E "SEARCHEXPR" "somefile")
The immediate issue you see is caused by the fact that echo
outputs the newline always. In the case where you get at least one line from the command substitutions, this actually helps, since command substitutions remove trailing newlines. It also works with tailing empty lines, try this to see: x=$(echo foo; echo; echo); echo "$x"
.
If you want to process the lines in the shell script in some other way, in addition to counting, then storing the text in a variable might not be best. You could try
for line in $lines ; do
something with "$line"
done
But that has the usual issues with unquoted variables, i.e. filename globbing and word splitting on whitespace. One line containing "foo bar doo", would be seen as three, since by default, the spaces split too.
You might want to use a while read
loop instead, but for that, a shell that supports process substitution might be good to have. See BashFAQ 001 and variable doesn't change after find & while and in bash, read after a pipe is not setting values .
add a comment |Â
up vote
4
down vote
Using CONTENTS
to hold the file just to echo
it again is a bit redundant, you could just
lines=$(cat "somefile" | grep -E "SEARCHEXPR")
or rather
lines=$(grep -E "SEARCHEXPR" "somefile")
If you just want the count of matching lines, use grep -c
count=$(grep -c -E "SEARCHEXPR" "somefile")
The immediate issue you see is caused by the fact that echo
outputs the newline always. In the case where you get at least one line from the command substitutions, this actually helps, since command substitutions remove trailing newlines. It also works with tailing empty lines, try this to see: x=$(echo foo; echo; echo); echo "$x"
.
If you want to process the lines in the shell script in some other way, in addition to counting, then storing the text in a variable might not be best. You could try
for line in $lines ; do
something with "$line"
done
But that has the usual issues with unquoted variables, i.e. filename globbing and word splitting on whitespace. One line containing "foo bar doo", would be seen as three, since by default, the spaces split too.
You might want to use a while read
loop instead, but for that, a shell that supports process substitution might be good to have. See BashFAQ 001 and variable doesn't change after find & while and in bash, read after a pipe is not setting values .
add a comment |Â
up vote
4
down vote
up vote
4
down vote
Using CONTENTS
to hold the file just to echo
it again is a bit redundant, you could just
lines=$(cat "somefile" | grep -E "SEARCHEXPR")
or rather
lines=$(grep -E "SEARCHEXPR" "somefile")
If you just want the count of matching lines, use grep -c
count=$(grep -c -E "SEARCHEXPR" "somefile")
The immediate issue you see is caused by the fact that echo
outputs the newline always. In the case where you get at least one line from the command substitutions, this actually helps, since command substitutions remove trailing newlines. It also works with tailing empty lines, try this to see: x=$(echo foo; echo; echo); echo "$x"
.
If you want to process the lines in the shell script in some other way, in addition to counting, then storing the text in a variable might not be best. You could try
for line in $lines ; do
something with "$line"
done
But that has the usual issues with unquoted variables, i.e. filename globbing and word splitting on whitespace. One line containing "foo bar doo", would be seen as three, since by default, the spaces split too.
You might want to use a while read
loop instead, but for that, a shell that supports process substitution might be good to have. See BashFAQ 001 and variable doesn't change after find & while and in bash, read after a pipe is not setting values .
Using CONTENTS
to hold the file just to echo
it again is a bit redundant, you could just
lines=$(cat "somefile" | grep -E "SEARCHEXPR")
or rather
lines=$(grep -E "SEARCHEXPR" "somefile")
If you just want the count of matching lines, use grep -c
count=$(grep -c -E "SEARCHEXPR" "somefile")
The immediate issue you see is caused by the fact that echo
outputs the newline always. In the case where you get at least one line from the command substitutions, this actually helps, since command substitutions remove trailing newlines. It also works with tailing empty lines, try this to see: x=$(echo foo; echo; echo); echo "$x"
.
If you want to process the lines in the shell script in some other way, in addition to counting, then storing the text in a variable might not be best. You could try
for line in $lines ; do
something with "$line"
done
But that has the usual issues with unquoted variables, i.e. filename globbing and word splitting on whitespace. One line containing "foo bar doo", would be seen as three, since by default, the spaces split too.
You might want to use a while read
loop instead, but for that, a shell that supports process substitution might be good to have. See BashFAQ 001 and variable doesn't change after find & while and in bash, read after a pipe is not setting values .
edited Jan 14 at 13:46
answered Jan 14 at 13:40
ilkkachu
49.8k674137
49.8k674137
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f417023%2fbetter-shell-solution-when-blank-lines-may-be-piped-to-wc%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
Can't the whole thing be replaced by
COUNT=$(grep -Ec "SEARCHEXPR" somefile)
?â steeldriver
Jan 14 at 13:36