0

This question already has an answer here:

Not sure why this is producing error. This is a test code emulating my real code. I want to write a wrapper for find and want to allow for any argument, so I'm wrapping each arg in single quotes.

#!/bin/bash

function find2 {

   ARGS="/usr/bin/find"
   while [[ $# -gt 0 ]]; do
      ARGS="$ARGS '$1'"
      shift
   done
   echo CALLING:  $ARGS
   $ARGS

}

find2 /tmp/test -name "hello.c"    # THIS IS THE DESIRED IMPLEMENTATION (doesn't work)

find '/tmp/test' '-name' 'hello.c'     # THIS IS FOR DEBUGGING (works)

I want to "find2" work, but it doesn't work. I get the following output:

CALLING: /usr/bin/find '/tmp/test' '-name' 'hello.c'
/usr/bin/find: `\'/tmp/test\'': No such file or directory
/usr/bin/find: `\'-name\'': No such file or directory
/usr/bin/find: `\'hello.c\'': No such file or directory

however, if I use the exact same command (produced by find2) directly, it works fine:

/tmp/test/hello.c

Not sure what is going on.

marked as duplicate by Gilles bash Mar 16 '16 at 22:39

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

0

(in Bash) You can change to an array of values:

find2() {

    ARGS="/usr/bin/find"
    ARGS+=( "$@" )
    echo CALLING:  "${ARGS[@]}"
    "${ARGS[@]}"

}

find2 /tmp/test -name "hello.c"

But this works and is quite simpler:

find2() {
    ARGS=( "/usr/bin/find" "$@" )
    echo CALLING:  "${ARGS[@]}"
    "${ARGS[@]}"
}

find2 /tmp/test -name "hello.c"

Of course, the direct way also work (in any shell with functions):

find2() {    /usr/bin/find "$@";   }

find2 /tmp/test -name "hello.c"

Why the original code failed?

To "see" what the code is doing you may use set -x or better yet , replace the echo for printf, as this:

find2() {

    ARGS="/usr/bin/find"
    ARGS+=( "$@" )
    printf '<%s> ' CALLING:  "${ARGS[@]}"; echo
    "${ARGS[@]}"

}

find2 /tmp/test -name "hello.c"

When you execute it, you see:

$ ./script.sh
<CALLING:> </usr/bin/find> </tmp/test> <-name> <hello.c> 

Each argument is a separate element (note the position of the <>).

However, in your original code (adding printf):

function find2 {

    ARGS="/usr/bin/find"
    while [[ $# -gt 0 ]]; do
        ARGS="$ARGS '$1'"
        shift
    done
    printf '<%s> ' CALLING:  "${ARGS[@]}"; echo
    $ARGS

}   

find2 /tmp/test -name "hello.c"

You will get, on execution:

$ ./script.sh
<CALLING:> </usr/bin/find '/tmp/test' '-name' 'hello.c'>

All the values are a long text line, not separate arguments (note the position of the <>).

  • so this works perfectly, plus I learned about this "$@" trick. it get the exact job done. thanks. but, can you explain WHY my original code did not work? it is not obvious to me why it should have failed in the first place, when typing the exact same string at a command line does work. – codechimp Mar 16 '16 at 17:36
  • Read the edited answer. – user79743 Mar 16 '16 at 19:26
0

If you change the line ARGS="$ARGS '$1'"to ARGS="$ARGS $1" (removing single quotes) it should work.

  • removing the single quotes is not an appropriate solution. my use of the single quote is deliberate: for when one of the argument has a space in it, like 'hello kitty.c' – codechimp Mar 16 '16 at 17:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.