This is the output
+ STATEMENT='cvs commit -m "This is" ../PBP/EIR.ENTRY'
+ echo cvs commit -m '"This' 'is"' ../PBP/EIR.ENTRY
cvs commit -m "This is" ../PBP/EIR.ENTRY
+ exit 0
Problem: Notice the single quotes between "This" and "is" ... This causes the called program "cvs" to think those are separate parameters which they are not.
bash does not parse quotes inside quotes or other forms of that sort of doublethink. To make it do so, you use eval.
The reason it doesn't parse quotes inside quotes and the like is the same reason eval tends to be avoided -- parsing syntax inside syntax leaves you open to someone injecting a `rm -Rf ~/` into your input and having your code execute that.
NOTE:
cvs = Concurrent Versions System
commit = commit to the cvs repository
-m = What follows in the quotes is the Log message for this revision
"This is" = the Log message for this revision
./q.sh = the file
This works:
#!/bin/bash -x
set -- cvs commit -m "This is the comment" ./q.sh
"$@"
exit 0
What I want to be able to do is dynamically create that whole string in the script and execute it.
This fails
#!/bin/bash -x
STATEMENT="set -- cvs commit -m \"This is the comment\" ./q.sh "
"$STATEMENT"
exit 0
This fails
#!/bin/bash -x
STATEMENT="set -- cvs commit -m \"This is the comment\" ./q.sh "
$STATEMENT
exit 0
This is so frustrating because it seems so simple. I am feeling like a not so bright person right now.
I suggested set -- as a replacement for putting the command in quotes. It's not a way to put the command in quotes.
What you want is not easy or straightforward for the reasons I already explained. Quotes are not usually a part of strings, quotes denote strings. If you want to give that command to a shell, run it in a shell.
A bourne shell will not evaluate quotes there without an eval, scrutinizer.
If you really wish to kludge it into running like that instead of just running it in the first place, you can feed it into a shell. This is not efficient and probably not the greatest idea.
-- @corona, You are right of course. I jumped in after the last post, because of the the set statement. I had not really read the problem at hand... I'll correct post #7...
Indeed eval is definitely a security risk, you would for example need to make sure that the variable content comes from a controlled source and not from user input or input files or any other source that you do not control or insufficiently control otherwise someone might gain access to the rights of the user executing the script.
So you would need to think if it isn't better to use a different setup that does not require the use of eval. So for example, just do not use the intermediate step of a command variable like $STATEMENT ( I personally never use those ), but execute the command directly without eval. If you do not like that, an alternative could be to create a function.
Yes. So the correct way to prevent this is to not do what you're doing -- not put quotes inside quotes, and have to parse the quotes inside quotes... Store the string in such a way you don't need eval, echo | sh, or other such trickery to parse it. Every alternative we've shown you, you've turned around and tried to store it in a string again, causing the same problems you had before. It's not the way in which you're storing it inside a string that's doing it... It's the fact that you're doing it at all. That doesn't work, no matter how you cut it, without needing to use walking security holes like eval.
Which brings me to the real question. Why do you need to store it in a string like this?
CVS has the ability to store commit messages for each version of a file. These messages tend to be very descriptive and are entered by the user explaining what they did to the file.
So, how would you suggest I get this information from the user as an input and pass it to cvs as a string?
I have tried to get this to the bare essentials. What I want to do is pass a string from a.sh to b.sh and echo that to the screen.
#!/bin/bash -x
#a.sh
echo $1
./b.sh $1
#!/bin/bash -x
#b.sh
echo $1
$a.sh "test multi"
+ echo test multi
test multi
+ ./b.sh test multi
+ echo test
test
Why can't I get this to work???????? I have gone back through this thread and the only one I can get to work is the "eval" which is too susceptible to attack. Sorry, but I am just getting frustrated with myself.
If you don't put strings in quotes, the shell splits on them on spaces. The quotes are not considered part of the string -- they define whether splitting happens or not inside it.
Substitution happens inside double quotes, but not single ones. So use double quotes here.
"$1"
Note that -x might not show the quotes anyway... This is because -- I repeat -- the quotes are not part of the string. They're delimiters. They define where one string stops and ends, but aren't included in the data itself.
I also note that if you'd used my code as given, it would have worked; it included quotes where necessary...
h
will attempt to commit filename "is" with message "This". So I do need the double quotes, right? They ARE part of the string I am passing to the cvs statement.
---------- Post updated at 03:27 PM ---------- Previous update was at 03:25 PM ----------
I do not mean to sound testy or petty, I am just very frustrated with myself right now. Please keep trying for me and my sanity sake. Thanks