1
page=`grep $x /var/www/vhosts/example.com/statistics/logs/access_log | awk '{print $7}'| sort |uniq -c |sort -nr`
times=`$page | wc -l`

I am trying to save output of grep in a variable as page.

But later I want to re-use that grep output to calculate some other thing.

Below code throws:

command not found

How can I fix the issue and reuse the output?

NecNecco
  • 701

2 Answers2

4

Because the page variable can contain arbitrary text, you shouldn't use echo, you should use printf.

times="$(printf %s\\n "$page" | wc -l)"

Also note that if you have more than one trailing newline in the output of your grep command, you won't get the expected result no matter what, because command substitution strips trailing newlines and the echo command or the printf command I use alike will add in exactly one trailing newline, regardless of how many were stripped from the grep output when the $page variable was being set.


Of course, even in this case the $times variable will contain a bunch of extra spaces at the start, because that's how wc -l will output its information. So this answer doesn't address the broader issue with your script: It looks like you are pressing bash into service where awk would serve better.

I could be wrong about that, depending on what you intend to do with the $times variable, but I seriously doubt it. Most likely you can do what you need (all of what you need) with an awk one-liner.

Wildcard
  • 36,499
  • I repeatedly recommend that all shell variable references (including $(…)) should be quoted (e.g., times="$(printf "%s\n" "$page" | wc -l)"), unless there is a good reason not to.  This is one of those special cases: since wc is fairly well behaved (except for its annoying habit of writing leading spaces), I recommend using times=$(printf "%s\n" "$page" | wc -l) (or, for example, num_lines=$(wc -l < "filename")) to get the shell to strip the spaces. – G-Man Says 'Reinstate Monica' Apr 07 '16 at 23:04
  • 2
    @G-Man, unfortunately that won't make any difference here. The double quotes around the variable don't actually do anything on the Right Hand Side of an assignment (though the rules with export are sometimes different); the shell won't word split the RHS regardless of quoting. So you'd still have the extra spaces. You could avoid the issue by leaving $times unquoted when it is used later, however. – Wildcard Apr 07 '16 at 23:12
  • 1
    True. Anyway, the question here is a dupe (I can't find the other one right now...) but for the record you can also use herestrings/heredocs if you want to reuse the output saved into a variable. Also, fwiw, in this particular case there should be no trailing empty lines. – don_crissti Apr 07 '16 at 23:20
  • @Wildcard Thank you very much for your answer. I have a boolean issue with this same manner. whois=\whois 100.43.81.149`; bool="$(printf %s\n "$whois" | grep -q netname:)" ; if $bool;then:fi` bool variable is always true although in this case it is not. Would you help please? – NecNecco Apr 11 '16 at 15:00
  • 1
    @NecNecco, please post a new question. (I will mention, though, that if takes a command, not a variable.) – Wildcard Apr 11 '16 at 15:23
  • http://unix.stackexchange.com/questions/275738/boolean-issue-for-grep – NecNecco Apr 11 '16 at 15:41
1

Updated: Revision for multi-line $page values, thanks @Wildcard!

You were very close on line 2. As long as your line 1 actually works, then for your second line you should try:

times="$(echo "$page" | wc -l)"

Explanation

  • $( and ) is command substitution, equivalent to were doing with the backticks, (in man bash these are referred to as backquotes), but I prefer $( ) because they are easier to spot in code
  • Just having $page will not pass anything to wc -l
  • Bash will instead think you want to run whatever is written in $page as a command and then passing that command's output to wc -l, so if $page contains 5 bla it will think 5 bla is a command. This would lead to errors such as those you found when you saw command not found
  • So to pass the value we can echo the $page variable
  • However if $page contains multi-line values, echo $page will by default result in losing those lines, they just become spaces
  • To avoid this undesired result, preserve the value and those new lines in $page by surrounding with quotes: echo "$page"

So, by using echo "$page", wc -l is then able to correctly receive $page's value.

clarity123
  • 3,539
  • 1
    This won't actually work without quoting "$page". It will always output "1". A newline is just a form of whitespace, and echo won't preserve it. (Actually, echo won't even see the newline.) – Wildcard Apr 07 '16 at 21:38
  • Good point, thanks @Wildcard, answer updated to include quoting "$page" – clarity123 Apr 07 '16 at 21:49