Shell arguments in variable vs direct string
Hello Community!
Let's say that we have some script which counts its arguments number: arguments_count.sh: Code:
#!/bin/sh test.sh Code:
#!/bin/sh Quote:
|
Well first...
If you run the script with debugging (-vx) options you would see why. You are getting what you asked for: Code:
$ sh -vx test.sh Code:
+ ./arguments_count.sh 1 2 3 ''\''4' '5'\''' 6 if you change the script "arguments_count.sh" to: Code:
#!/bin/sh The issue is understanding how the shell expands variables for use. And it does get tricky to pass arguments with "special" characters embedded (space/tab - as well as others like ()&; ...). What you saw was that the '4 is passed as a single argument... and 5' was passed as the other. But when passed directly, the '4 5' was interpreted as you expected. It takes practice -- and quite frequently making a test case is the only way to see what actually happens. This is also one of the reasons shell scripts cannot be considered for "secure" use. It is too easy to overlook a loophole (try embedding the string `ls` as a parameter and see what happens...) |
Escape or quote the quotes:
Escape: ./arguments_count.sh 1 2 3 \'4 5\' 6 Quote (note this is single quote followed by single quote NOT double quote): ./arguments_count.sh 1 2 3 ''4 5'' 6 Often when running things within levels (e.g. a script within a script) you have to escape or quote to be sure the literal things you are passing (in this case your single quotes around 4 5) make it through to the next level. |
Quote:
How can I get this to work well? |
This is not obvious... and may not be the best way...
If you replace the following line in the test.sh script Code:
./arguments_count.sh $my_args Code:
eval ./arguments_count.sh $my_args This approach may not even work in all cases - as the space character between the 4 and 5 will have been evaluated, so if you expected to pass a tab character it won't be there as previous evaluations removed it. This will not help if have multiple nested structures... Easier to use perl or python.. |
Quote:
Code:
my_args='1 2 `do_something_evil` 4 5' Code:
my_args=(1 2 3 '4 5' 6) Code:
./arguments_count.sh "1" "2" "3" "4 5" "6" |
Quote:
I parsed argument in single quatas into separate variable and then use, it is working good, unfortunately is not so flexible. Tomorrow I will post details about my solution (with example code). Maybe someone will point me improvements. |
Quote:
Quote:
|
Quote:
The POSIX bourne shell doesn't have arrays... |
As it has not really been explained why this is necessary it is more difficult to know why we need to mold this particular answer in this way.
So my suggestion would be to quote the variable and thereby preserve the quotes and then write your own function to parse the data to your own specification. |
Hello Community!
Below You can find my solution for the problem: test_parse.sh: Code:
#!/bin/sh Problem with my solution is that is only allow parsing arguments string which consist only one (or none) expression with single quotas. Anyway my problem is solved but not for future. Short explanation of the root cause: I have some configuration file. One of the scripts analyses the file and searches for some daemon arguments. When the script finds the arguments it runs the demon with some fixed arguments combined with founded arguments. User can write in configuration file arguments which consist single quoted text (argument in single quotes is short script indeed). Some time ago there was a change of the read and write configuration method. Now I found that some old configuration doesn't work properly because of the problem with interpretation of single quotes in variable. If You are interested in details it is about pppd daemon and argument "connect <connect_script>"(check man for pppd). You can create connect script and put path to it. You can also put some short script in single quotas instead of the path. For example: connect_script: Code:
#!/bin/sh Code:
pppd arg1 arg2 arg3 connect /path/to/connect_script arg4 arg5 & Code:
pppd arg1 arg2 arg3 connect 'chat -v -f /somefile.chat' arg4 arg5& I cannot change old configuration file and replace quotas with path to script. That is why I have to modify method of read daemon arguments. Shell which uses daemon arguments read script is POSIX compatible. |
Quote:
test.sh: Code:
#!/bin/sh |
usually this:
Code:
my_args_in_quote=`echo ${my_args:$my_args_quote_pos}` First, you need to use ", next `echo something` is usually equal to something without echo and ` (backtick). Also backtick makes some tricks on the command in between backticks, so you need to take extra care. [[ ]] is preferred (instead of [ ] ) So your code should look like this: Code:
my_args_before_quote="${my_args:0:$((my_args_quote_pos-1))}" #store args before single quote char looks like you want to modify the original behaviour (of bash), so just go back to the original question: Code:
#!/bin/sh 1 2 3 4 5 << here ' ' will protect the space between 4 and 5 to use as separator 6 in the first case you will have 1 2 3 '4 5' 6 because " will force the interpreter to use ' as is, loosing its special meaning (as it was used in the first case). Also you may try: ./arguments_count.sh "$my_args" which will return 1, because the whole string will be used "in one", as a single argument. Every time you start a command this argument parsing will occur and that's why embedding argument lists into each other is not really trivial (backtick will also do something like this) - although not impossible. You need to keep embedded commands+its arguments in one as long as it is just passed to another command. The usual way is to protect " against evaluation by escaping it (using \ and/or '). http://wiki.bash-hackers.org/syntax/quoting http://stackoverflow.com/questions/9...ring-quotation http://www.tldp.org/LDP/abs/html/quotingvar.html http://stackoverflow.com/questions/1...quoted-strings (and obviously you can find a lot of other examples) I hope this helps a bit |
Probably just me not following, but are you saying that the current config files will have the line:
Code:
chat -v -f /somefile.chat be quoted? I would have thought that if trying to future proof you would also need to consider the scenario where there are more than 1 set of quoted information? |
Quote:
There can be max 3 sets with quotes (pppd 2.4.7): connect 'something' disconnect 'else' init 'another' But solution with "storing whole command into another script" does the trick. |
All times are GMT -5. The time now is 07:26 AM. |