0

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.

codechimp
  • 207

2 Answers2

0

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

mnille
  • 529
  • 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
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. –  Mar 16 '16 at 19:26