Results 1 to 10 of 10
I am trying to write a wrapper for a program (cvs) using bash. At the end of the script, I need to call the original program with the command-line arguments ...
- 06-07-2006 #1Just Joined!
- Join Date
- Jun 2006
- Posts
- 5
bash script problem: preserving quotes from arguments
I am trying to write a wrapper for a program (cvs) using bash. At the end of the script, I need to call the original program with the command-line arguments that were passed to the script ($@). The problem is that some of the arguments have multiple words inside quotes (such as -m "this is a message"). If I do "program $@", then the quotes aren't passed to the program, and it can't parse the options. I have tried putting quotes around $@, and using $* as well, but I couldn't get bash to do what I want. Any suggestions?
Here is the code in case it will help you. Even though I save the arguments in $OPTIONS, I get the same results when using $@ or $* directly.
Code:#!/bin/sh #cvs [ cvs_options ] cvs_command [ command_options ] [ command_args ] OPTIONS="$*" # Strip off cvs_options until [ -z "$1" ] do if [ "${1:0:1}" = "-" ] ; then if [ $1 = "-b" -o $1 = "-d" -o $1 = "-e" -o $1 = "-z" ] ; then shift fi shift continue fi break done if [ -z "$1" ] ; then cvs $OPTIONS #No options? Let CVS deal with it... exit $? fi # Check cvs_command, execute it if not commit if [ "$1" != "commit" ] ; then cvs $OPTIONS exit $? fi # Check if files were given #[-lnR] [-m 'log_message' | -f file] [-r revision] [files...] shift until [ -z "$1" ] do if [ "${1:0:1}" = "-" ] ; then if [ $1 = "-f" -o $1 = "-r" -o $1 = "-m" ] ; then shift fi shift continue fi break done if [ ! -z "$1" ] ; then cvs $OPTIONS exit $? fi # Read cvs status FILES=`cvs -n -q update` # Print warning echo "Your commit will include/exclude the following files:" echo "$FILES" echo # Get answer ans="?" until [ "$ans" = "y" -o "$ans" = "n" ] do echo "Are you sure you want to commit? [y/n]" read ans done # Perform command if "y" if [ "$ans" = "n" ] ; then echo "Not executing commit (aren't you happy you used this script?)" else cvs $OPTIONS fi
- 06-07-2006 #2
Could you use $1, $2 etc and build up $OPTIONS using a for loop and some double quotes? (You will have to escape the double quotes inside OPTIONS with a \)
All the best
- 06-07-2006 #3Just Joined!
- Join Date
- Jun 2006
- Posts
- 5
It's a pain, and I didn't think it would work, so I didn't try. I'll give it a shot though. Will update with results.
Originally Posted by birdman
Thanks.
- 06-07-2006 #4Just Joined!
- Join Date
- Jun 2006
- Posts
- 5
I managed to recreate $OPTIONS. It's pretty hacky, but maybe it's good enough. When I print $OPTIONS, I see the quotes where they should be. Unfortunately, when I execute `cvs $OPTIONS`, it still behaves as if the quotes weren't there. Here is the code that I added to the beginning of the script:
Code:countargs () { return $# } for (( i = 1; i <= $# ; i++ )) do eval VAR=\$$i countargs $VAR words=$? if [ "$words" -ge "2" ] ; then OPTIONS="$OPTIONS \"$VAR\"" else OPTIONS="$OPTIONS $VAR" fi done
- 06-07-2006 #5
Does it work when you type in the parameters using double quotes without the script? (i haven't used cvs before)
You could try single quotes also - apart from that I am a little stuck as to why this wouldn't work.
- 06-08-2006 #6Just Joined!
- Join Date
- Jun 2006
- Posts
- 5
Single quotes didn't work either. Here is a similar script, grepwrap.sh, that uses grep instead of cvs:
Originally Posted by birdman
Here is what happens from the command line:Code:#!/bin/sh countargs () { return $# } for (( i = 1; i <= $# ; i++ )) do eval VAR=\$$i countargs $VAR words=$? if [ "$words" -ge "2" ] ; then OPTIONS="$OPTIONS \"$VAR\"" else OPTIONS="$OPTIONS $VAR" fi done echo $OPTIONS grep $OPTIONS
$ echo "hello 1 there" > foo
$ ./grepwrap.sh "hello there" foo
"hello there" foo
grep: there": No such file or directory
$ grep "hello there" foo
$
So the quotes are in OPTIONS now, but they aren't being interepreted correctly.
- 06-08-2006 #7
Looked at this and cannot find an answer (I have even tried hex and octal but to no avail)
I was looking for some way to see if we can store the not already interpreted double quotation mark, as I believe your problem lies in the fact that the double quote is already text and is interpreted by the shell as such. This is tough.
Any bash gurus out there?
- 06-08-2006 #8Linux Engineer
- Join Date
- Apr 2006
- Location
- Saint Paul, MN, USA / CentOS, Debian, Solaris, SuSE
- Posts
- 1,065
Hi.
I think $@ will do what you wish, but you'll need to invoke the magic string that includes quotes, namely
Here's a driver script and a small script that simulates what I take your script to be. I use ":" to put markers around strings so that I can see the boundaries, including spaces:Code:"$@"
And here is script it callsCode:#!/bin/bash # @(#) drive demo arg processing. ./s1 hello ./s1 "hello world" ./s1 "first phrase" "second phrase"
The outputCode:#!/bin/bash # @(#) s1 Show argument processing. echo echo " Args plain" echo :$*: echo echo ' Args from "$*" (note quotes)' i=1 for arg in "$*" do echo "arg $i is :$arg:" let "i+=1" done echo echo ' Args from "$@" (note quotes)' echo :"$@": i=1 for arg in "$@" do echo "arg $i is :$arg:" let "i+=1" done
See positional argument section in man bash for more details. If necessary in your situation, you could then enclose $1, $2 in quotes to preserve the spaces to use as arguments to another script ... cheers, drlCode:% ./drive Args plain :hello: Args from "$*" (note quotes) arg 1 is :hello: Args from "$@" (note quotes) :hello: arg 1 is :hello: Args plain :hello world: Args from "$*" (note quotes) arg 1 is :hello world: Args from "$@" (note quotes) :hello world: arg 1 is :hello world: Args plain :first phrase second phrase: Args from "$*" (note quotes) arg 1 is :first phrase second phrase: Args from "$@" (note quotes) :first phrase second phrase: arg 1 is :first phrase: arg 2 is :second phrase:
Welcome - get the most out of the forum by reading forum basics and guidelines: click here.
90% of questions can be answered by using man pages, Quick Search, Advanced Search, Google search, Wikipedia.
We look forward to helping you with the challenge of the other 10%.
( Mn, 2.6.n, AMD-64 3000+, ASUS A8V Deluxe, 1 GB, SATA + IDE, Matrox G400 AGP )
- 06-13-2006 #9Just Joined!
- Join Date
- Jun 2006
- Posts
- 5
Thanks
"$@" did the trick. I was still unable to reconstruct it properly, so I used a counter for the parameters instead of shifting and using $1. Whenever I had to call cvs, I did:
Thanks to both of you for your help.Code:cvs "$@"
- 02-21-2009 #10Just Joined!
- Join Date
- Feb 2009
- Posts
- 1
I needed argument escaping
I was writing an SSH wrapper script, and for the life of me could not get quoted arguments to be passed through properly.
I finally found a solution involving awk and escaping EVERY character of EVERY argument:
Surprisingly, this is quite bullet broof, and properly escapes strings and preserves arguments like:Code:#!/bin/sh CMD="" for (( i = 1; i <= $# ; i++ )); do eval ARG=\$$i CMD="$CMD $(echo "$ARG" | awk '{gsub(".", "\\\\&");print}')" done ssh my_machine cd /my/path \&\& RAILS_ENV=production $CMD
./remote.sh grep "hello there" . -R
./remote.sh grep "So I says to the typewriter, \"Hey, I'm in quotes\"" . -R
./remote.sh grep "\"" . -RLast edited by timcharper; 02-21-2009 at 12:15 AM. Reason: Clarification



