LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   [SOLVED] bash script: can echo command, command works if I type, but command doesn't work in script ... why? (https://www.linuxquestions.org/questions/linux-newbie-8/%5Bsolved%5D-bash-script-can-echo-command-command-works-if-i-type-but-command-doesnt-work-in-script-why-4175568932/)

hopeless_n00b 02-01-2016 10:27 AM

[SOLVED] bash script: can echo command, command works if I type, but command doesn't work in script ... why?
 
My goal is to understand what is going on:
The following script is given the name 'marg':

------------------------------------------------
#!/bin/bash

d=$(dirname "$1")
b=$(basename "$1")

echo find "$d" -name ""$b"" -type f -print
------------------------------------------------

If I type

marg './foo/*' bar/

in an xterm, the result is

find ./foo -name "*" -type f -print

If I type the above command into an xterm it executes ok.

But if I change marg to
------------------------------------------------
#!/bin/bash

d=$(dirname "$1")
b=$(basename "$1")

find "$d" -name ""$b"" -type f -print
------------------------------------------------

then If I type

marg './foo/*' bar/

in an xterm, the result is that the find command does not execute.

WHY?

P.S. For those wondering "what am I trying to do?" the answer is: I am trying to understand what is going on with the above.

P.P.S. I have spent time looking online and reading man pages, but I obviously do not understand the fundamental principles... could some kind soul walk me through exactly what is going on and why removing the echo from the script does not result in the find command working?

suicidaleggroll 02-01-2016 11:05 AM

Remove the second set of quotes around $b in your find, they're messing things up. I think your intention is to add quotes into the command, but of course you can't nest quotes like that. "" is just an empty string, so you have [empty string]*[empty string]. Since the asterisk isn't quoted, it's being treated as a globbing pattern, rather than a literal asterisk, which is screwing up the find.

Also, add "set -x" at the top of your script after the shebang for testing things like this.

Code:

#!/bin/bash
set -x

d=$(dirname "$1")
b=$(basename "$1")

find "$d" -name "$b" -type f -print


hopeless_n00b 02-01-2016 11:22 AM

Thanks... I think you got me over my sticking point.

Habitual 02-01-2016 11:25 AM

Code:

bash -x /path/to/script.sh
works too I believe. :)

josephj 02-01-2016 10:29 PM

A few additional thoughts
 
If you needed to use echo (e.g. if there were other strings to add ... )

Code:

echo "I found [" $(find "$d" -name "$b" -type f -print) "]"
(Note that the quotes are fixed as per @suicidaleggroll.)

Also, note that your example

Code:

marg './foo/*' bar/
calls marg with two arguments because there is white space between ' and bar/.

Since your script only has one argument, the second one is ignored (after it is expanded). That's why you don't see bar anywhere in your example output.

In line with @habitual's suggestion,

I have a file called bash_trace in my ~/bin directory which contains:

Code:

shopt -s -o xtrace  # debug
shopt -s -o verbose  # debug

If I have a script I will use more than once or that needs work, I often include the line

Code:

##source "~/bin/bash_trace" ## debug
in it somewhere near the top. Then, whenever staring at the code isn't enough, I just uncomment that line and run it again to get a full trace. This lets me set and unset both options just by uncommenting or commenting out one line.

The source statement or just plain . tells bash to read that file as if it was part of the script - just like an include statement in other languages.

The shopt sets shell options. (There are a lot of them.) -s stands for set or turn on and -o says which option to affect.

verbose is the same as the -v command line option which prints shell command lines as they are read.

xtrace is the same as the -x command line option which prints the command line after it has been expanded.

This lets you see the command the way you wrote it and then shows you what "marvelous" things bash did to expand it before actually trying to execute it.

gyles19 02-03-2016 04:07 PM

Install the bashdb package for your distro, and use it to single-step through scripts, inspect variables, etc. It's not perfect but it's usually quite informative, especially if you put -xv on your hashbang inside the script being debugged.

Norseman01 02-05-2016 03:58 PM

some additional thoughts
 
[QUOTE=hopeless_n00b;5491087]My goal is to understand what is going on:
The following script is given the name 'marg':

...skip

#!/bin/bash

d=$(dirname "$1")
b=$(basename "$1")

find "$d" -name ""$b"" -type f -print
------------------------------------------------
...skip
then If I type
marg './foo/*' bar/

...skip
===========================

In your initial question you use:

marg './foo/*' bar/

Legacy bash states that something enclosed in apostrophes is to be taken litterly
and those between quotes is to be expanded.
for those who had bad English teachers:

..apostrophe(s) is/are also referred to as single quote(s)
..quote(s) is/are also referred to as double quote(s).

since you are using bash to differentiate the path and the filename anyway, you probably should simply make the marge call:
..marge "./foo/*bar" #assumes filename ends in anythingbar
... or
..marge "./foo/*.bar" #assumes filename ends in .bar
... or
..marge "./foo/*bar*" #assumes seeking anythingbaranything

the echo should be removed because find could return a few thousand matches and
-print does the echo part anyway. :)

I add the echo to the front of search loop commands to check if the loop is going to do what I think it will rather than what it actually got told. :) Once bash and I agree on the desired results I remove the echo from the front of the command line (the find line in your case) and send it off to work.


Norseman01

cesarbergara 02-26-2016 01:01 PM

Hi. "" Are special characters. All you put between them are literal. You can put "'" and "" or "$" when you need show those specials characters (if you have a variable VARIABLE, you can show variable contents with:
echo $VARIABLE
or show variable name with:
echo "$VARIABLE"

Without "", \ convert next character from special in normal, for example, in empty space:
HI\ MY\ NAME
Try with:

VAR1="HI MY NAME" ; echo $VAR1; unset VAR1; echo $VAR1
VAR1=HI\ MY\ NAME ; echo $VAR1; unset VAR1; echo $VAR1
VAR1=HI MY NAME ; echo $VAR1; unset VAR1; echo $VAR1
VAR1=HI"" MY"" NAME ; echo $VAR1; unset VAR1; echo $VAR1
VAR1=HI"\ "MY "\ "NAME ; echo $VAR1; unset VAR1; echo $VAR1

and you can see differences.

You can find lot of combinations with special characters (" , ' , \ , $ , % , & ; etc) in:
man bash


Have a nice day.

suicidaleggroll 02-26-2016 01:09 PM

Quote:

Originally Posted by cesarbergara (Post 5506673)
Hi. "" Are special characters. All you put between them are literal. You can put "'" and "" or "$" when you need show those specials characters (if you have a variable VARIABLE, you can show variable contents with:
echo $VARIABLE
or show variable name with:
echo "$VARIABLE"

Incorrect

double quotes do not prevent variable substitution.
echo $VARIABLE
and
echo "$VARIABLE"
will provide the exact same output.

single quotes are what prevents variable substitution.

grail 02-26-2016 01:11 PM

Please use Thread tools to actually mark the question as SOLVED

tarvinder91 07-12-2018 05:57 AM

solved
 
Thanks a lot. I have always used echo to see what my command will actually look like. However set -x should be used to see what actual command is running.


All times are GMT -5. The time now is 03:16 AM.