Find the answer to your Linux question:
Results 1 to 6 of 6
Basically, I have a program that will quite likely take multiple arguments with multiple spaces in them. These arguments are directory names, and as such when using bash the spaces ...
  1. #1
    Linux Newbie egan's Avatar
    Join Date
    Feb 2009
    Location
    Mountain View, CA
    Posts
    132

    BASH: Process arguments with escaped spaces

    Basically, I have a program that will quite likely take multiple arguments with multiple spaces in them. These arguments are directory names, and as such when using bash the spaces are escaped with '\'.

    I use a for loop to process each directory argument, and since they have spaces I use $@ instead of $*. Adding debug echoes show that this indeed works, each argument being extracted from the list. The problem is that for some reason, the argument is being extracted without escaped spaces, and as such the rest of the program will not work.
    Code:
    for DIRARG in $@
    do
             # some stuff
    done
    and $DIRARG has unescaped spaces in it.

    I am wondering if there is anyway to get it to keep the escapes in there so that the rest of the functions can get it.

    I am not entirely sure of my general program method either, so here is some code scrawl if anyone wants to give pointers; be them on my specific problem, or on a better way to get this done. The reason I am writing this is so that I can easily set up playlists with mplayer.
    Code:
    mplayer enum music/rec/Johannes\ Brahms/Clarinet\ Quintet\,\ op.\ 115/
    Will result in a list of movements being passed to mplayer. I would think there would be a command to do this, but I didn't find anything.

    Code:
    #!/bin/bash
    
    ##
    # enum -- enumerate file paths to stdout
    #
    # usage -- enum [DIRS]
    #
    # notes -- really messy!
    #
    # written -- 8 August, 2009 by Egan McComb
    #
    # revised --
    ##
    
    ERR_NARGS=3
    ERR_VARGS=5
    
    LISTCOMMAND="ls --quoting-style=escape"
    
    SAVEIFS=$IFS
    IFS=`echo -en "\n\b"`
    
    usage()
    {
    	echo "Usage: $0 [DIRS]" >&2
    }
    
    chkargc()
    {
    	if [ -z $1 ]
    	then
    		echo "Error: Too few arguments" >&2
    		usage
    		exit $ERR_NARGS
    	fi
    }
    
    chkargs()
    {
    	if [ ! -d $1 ]
    	then
    		echo "Error: Invalid directory '$1'" >&2
    		usage
    		exit $ERR_VARGS
    	fi
    }
    
    listdir()
    {
    	echo `eval $LISTCOMMAND $*`
    }
    
    catpath()
    {
    	DIRPATH=$1
    	shift
    	for FILEARG in $@
    	do
    		FILEPATH="${DIRPATH}${FILEARG}"
    		# XXX: Security vulnerability?
    		OUTFILE="$OUTFILE $FILEPATH"
    	done
    	echo $OUTFILE
    }
    
    enumerate()
    {
    	echo $*
    	LIST=`listdir $*`
    	echo `catpath $* $LIST`
    }
    
    ##----MAIN----##
    
    chkargc $*
    
    # XXX XXX XXX: DIRARG does not retain escapes!
    for DIRARG in $@
    do
    	chkargs $DIRARG
    
    	# XXX: Security vulnerability?
    	OUTDIR="$OUTDIR `enumerate $DIRARG`"
    	echo $OUTDIR
    done
    
    IFS=$SAVEIFS
    
    exit 0
    This was not the original state of the code, but a result of me trying to isolate the problem. The security vulnerability comments are due to the fact that OUTFILE or OUTDIR might already have something in them, and I don't check if they are empty because I was lazy and didn't want to write to routines to initially fill or to append to them.

    Any advice or insight is greatly appreciated.

  2. #2
    Trusted Penguin Cabhan's Avatar
    Join Date
    Jan 2005
    Location
    Seattle, WA, USA
    Posts
    3,230
    You are almost right! The problem is that for $@ to keep its special properties, it must be _quoted_ (and as a note, you should almost always quote your variables).

    Therefore, try this instead:
    Code:
    for DIRARG in "$@"
    do
    	chkargs $DIRARG
    
    	# XXX: Security vulnerability?
    	OUTDIR="$OUTDIR `enumerate $DIRARG`"
    	echo $OUTDIR
    done
    Now, $DIRARG will not have its escapes, but that's okay! You simply need to quote the variable whenever you use it: this accomplishes the same thing as escaping. So, for instance, say:
    Code:
    enumerate "$DIRARG"
    instead of:
    Code:
    enumerate $DIRARG
    Does this make sense?
    DISTRO=Arch
    Registered Linux User #388732

  3. #3
    Linux Newbie egan's Avatar
    Join Date
    Feb 2009
    Location
    Mountain View, CA
    Posts
    132
    Quote Originally Posted by Cabhan View Post
    You are almost right! The problem is that for $@ to keep its special properties, it must be _quoted_ (and as a note, you should almost always quote your variables).

    Therefore, try this instead:
    Code:
    for DIRARG in "$@"
    do
    	chkargs $DIRARG
    
    	# XXX: Security vulnerability?
    	OUTDIR="$OUTDIR `enumerate $DIRARG`"
    	echo $OUTDIR
    done
    Now, $DIRARG will not have its escapes, but that's okay! You simply need to quote the variable whenever you use it: this accomplishes the same thing as escaping. So, for instance, say:
    Code:
    enumerate "$DIRARG"
    instead of:
    Code:
    enumerate $DIRARG
    Does this make sense?
    That does indeed make sense, but I still cannot get it to work...

    The more I fiddle with this, the more convoluted it gets. Does anyone have a simple solution to the problem this program sets out to solve. Maybe I will come back with fresh eyes to rewrite the whole thing with quoting in mind.

    Thanks for the help.

  4. #4
    Linux Newbie egan's Avatar
    Join Date
    Feb 2009
    Location
    Mountain View, CA
    Posts
    132
    Sure enough I may have found something to invalidate this whole thing, but unfortunately I am stuck in Windoze at the moment so I cannot test. Would:

    Code:
    mplayer music/rec/Béla\ Bartók/Piano\ Concerto\ No.\ 1/*
    work?

    I think that bash does the file globbing before it even passes the argument to mplayer?

  5. #5
    Linux User
    Join Date
    May 2008
    Location
    NYC, moved from KS & MO
    Posts
    251
    @egan, try to use quotation marks for $@ and command line argument. Take the following bash script for example (let's name it prog1):
    Code:
    #!/bin/bash
    echo "listing files under $@"
    ls "$@" -l
    To list a directory (with or without spaces), call the script this way:
    Code:
    prog1 "my directory 1"
    Ref: How to iterate over arguments in bash script - Stack Overflow

  6. #6
    Linux Newbie egan's Avatar
    Join Date
    Feb 2009
    Location
    Mountain View, CA
    Posts
    132
    Thanks for the help. I will keep in mind if I need to write a program that takes spaces... the program I was writing is usesless now that I confirmed that globbing works fine (for some reason it looked like I needed to write a program the last time I tried...)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...