3

I'm trying to use grep in a bash script and assign the result to a variable:

RESUlT=$(grep -R -I --exclude-dir=addons "^[^#]*print(" )

But it returns

bash: Map/Places/place.gd:: No such file or directory

I tested it in my terminal and

grep -R -I --exclude-dir=addons "^[^#]*print("

returns what I expect, but

$(grep -R -I --exclude-dir=addons "^[^#]*print(" )

returns the error.

I have no idea why that happens.

My whole Script:

#!/bin/bash

CYAN='\033[0;36m'
RED='\033[0;31m'
NC='\033[0m' # No Color

RESUlT=$(grep -R -I --exclude-dir=addons "^[^#]*print(" )
echo "${RESULT}"
echo -e "${CYAN}I ${RED}love${NC} Stack Overflow"

What bash does:

**bash -o xtrace .check_code.sh** 
+ CYAN='\033[0;36m'
+ RED='\033[0;31m'
+ NC='\033[0m'
++ grep -R -I --exclude-dir=addons '^[^#]*print('
+ RESUlT='Map/Places/place.gd:  print("enter")'
+ echo ''

+ echo -e '\033[0;36mI \033[0;31mlove\033[0m Stack Overflow'
I love Stack Overflow

One weird thing in the Terminal:

whereis grep

returns

grep: /usr/bin/grep /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz

But:

$(whereis /usr/bin/grep)

returns

Command 'grep:' not found, did you mean:
  command 'grep' from deb grep (3.11-2)
Try: sudo apt install <deb name>
9
  • Try running your script with bash -o xtrace path/to/the/script to see what is actually done. Commented Jun 27, 2024 at 10:16
  • Note that none of -R -I --exclude-dir are standard grep options. Make sure your script calls the grep implementation that supports those extensions. Commented Jun 27, 2024 at 10:18
  • Make sure there's no whitespace around the = in RESULT=$(... Commented Jun 27, 2024 at 10:19
  • 1
    What file does it (what? grep? the shell?) report not to exist? Commented Jun 27, 2024 at 10:19
  • What's the full and exact error message? (There should be more than just "No such file or directory".) Commented Jun 27, 2024 at 13:52

1 Answer 1

6

Nothing weird there, just the command substitution working.

When you tested the command

$(grep -R -I --exclude-dir=addons "^[^#]*print(" )

the shell first performed the command substitution on the command line before actually attempting to execute the command line after transforming it with the command substition.

From your bash -o xtrace ... output, I can see that executing the command within the parenthesis results in output:

Map/Places/place.gd:  print("enter")

In other words, grep found an uncommented print( string in a file named Map/Places/place.gd, as part of a line containing print("enter").

Then, grep's output output is inserted in place of the $( ... ) command substitution expression in the original command line. Because the entire command line is enclosed in $( ... ), the entire command line is replaced with the output above.

Then, the shell attempts to execute the transformed command line. Because there was nothing but the command substitution expression in the original command line, the shell ends up attempting to execute the output of the command that was within the command substitution expression as the actual command.

In other words, it will attempt to find an executable with a current-directory-relative pathname of Map/Places/place.gd: and give it print("enter") as the first argument.

You probably don't have any file named place.gd: (with the colon included in the filename). Because that does not exist, the shell displays an error message. Effectively, it says:

"I'm bash, and I have a problem with the Map/Places/Place.gd: you just told me to execute: There is No such file or directory."

It just displays this in a slightly more terse form:

bash: Map/Places/place.gd:: No such file or directory

In your script, look at these two lines:

RESUlT=$(grep -R -I --exclude-dir=addons "^[^#]*print(" )
echo "${RESULT}"

The output of the command within the $( ... ) command substitution expression is stored in the shell variable RESUlT. Then, in the next line, you are telling the shell to output the contents of a different variable RESULT. Yes, they are different: note the lower-case l in the first variable name.


The "one weird thing in the Terminal" is just the same as the error in your first terminal test.

The first command line

whereis grep

returns the output:

grep: /usr/bin/grep /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz

The second command line

$(whereis /usr/bin/grep)

will first run the same command as the first command line, capture its output, replace the command substitution expression with the output, and then attempt to execute the resulting command line.

Since the command line has now been transformed to

grep: /usr/bin/grep [...etc...]

the shell now attempts to find the command grep: (with the colon). Since there are no slashes in the "command", the directories listed in $PATH are searched, and then apparently then a helper function from the optional command-not-found package kicks in.

It produces a more verbose error message with some suggestions, identifying that grep: might have been grep with a mistyped colon appended, and if that's not the command you're looking for, you might need to install a package that contains the command you want. But in this case, those suggestions are not applicable, because you effectively tried to blindly execute the output of another command.

4
  • 1
    This doesn't explain why they get an error when assigning the result of the command substitution to a variable. Commented Jun 27, 2024 at 22:48
  • @Barmar you almost certainly have a space after the = in what is supposed to be an assignment: RESUlT= $(grep...) Commented Jun 28, 2024 at 1:48
  • In this case, I believe the bash -o xtrace .check_code.sh output more than OP's exact words. I'm guessing they ran the script, wondered about why their echo "${RESULT}" line produced no output, then tested the previous line by first running the command within the command substitution expression, and then the command substitution expression stand-alone (and got an error from trying to execute the value that was supposed to go into ${RESULT} variable in the original script), and then got confused about what the test results meant. The problem is in the OPs concept of how $(...) works. Commented Jun 28, 2024 at 4:01
  • Thanks for your help, it was the misspelling of RESUlT Commented Jul 9, 2024 at 20:02

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.