Bash – Shell Variable Not Passed to Subshell in find exec sh

argumentsbashfunctionquoting

Here is a simplified code that prints the name of Directory if it contains a Filename with same name as the parent directory and .md extension.

FIND(){
    find . -type d -exec sh -c '
        for d do
            [ -f "${d}/${d##*/}.md" ] && printf "%s\n" "$d"
        done' find-sh {} +
}


FIND

To generalize I want to send the Search term ${d}/${d##*/}.md as an argument to the FIND function, but unfortunately this does not outputs anything:

FIND(){
    local SearchTerm="${1}"
    find . -type d -exec sh -c '
        for d do
            [ -f "${SearchTerm}" ] && printf "%s\n" "$d"
        done' find-sh {} +
}

FIND '${d}/${d##*/}.md'

I am sure there is some issue with the quotation of the SearchTerm. Any hints?


I tried: FIND '\${d}/\${d##*/}.md' but has no output

Best Answer

The in-line script that you call is single-quoted (as it should be). This means that the sh -c shell will get a script where "${SearchTerm}" is unexpanded. Since that shell does not have a SearchTerm variable, its value will be empty.

Since you tagged your question with , you can pass the name of an exported function:

# Our find function.
# Takes the name of a test function that will be called
# with the pathname of a directory.
myfind () {
    local thetest="$1"

    # Run find, passing the name of the function into the in-line script.
    find . -type d -exec bash -c '
        testfunc=${1:-:}; shift
        for dirpath do
            "$testfunc" "$dirpath" && printf "%s\n" "$dirpath"
        done' bash "$thetest" {} +
}

# Our test function.
test_md_file () {
    [ -f "$1/${1##*/}.md" ]
}
export -f test_md_file

# Run the thing.
myfind test_md_file

The testfunc=${1:-:} in the code will assign $1 to testfunc if it's available and not empty, otherwise, it will use : as the test (a no-op utility that returns true).

Related Question