exec sh 찾기: 쉘 변수가 서브쉘로 전달되지 않았습니다.

exec sh 찾기: 쉘 변수가 서브쉘로 전달되지 않았습니다.

다음은 상위 디렉토리 및 확장자와 동일한 파일 이름이 포함된 경우 디렉토리 이름을 인쇄하는 단순화된 코드입니다 .md.

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


FIND

${d}/${d##*/}.md간단히 말해서, 검색어를 함수의 인수로 보내고 싶지만 FIND안타깝게도 아무 것도 출력되지 않습니다.

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'

나는 인용문에 몇 가지 문제가 있다고 확신합니다 SearchTerm. 어떤 팁이 있나요?


시도했지만 FIND '\${d}/\${d##*/}.md'출력이 없습니다

답변1

"${SearchTerm}"sh -c '다음과 같이 추론을 하려면 외부에 있어야 합니다 .

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'

이를 좀 더 설명하기 위해 간단한 테스트를 실행할 수 있습니다.

SearchTerm='${d}/${d##*/}.md'
echo 'Before "$SearchTerm" After'
# output : Before "$SearchTerm" After
echo 'Before "'"$SearchTerm"'" After'
# output : Before "${d}/${d##*/}.md" After

'Before "$SearchTerm" After'는 모두 작은따옴표로 묶여 있으므로 매개변수 확장이 없는 단일 문자열입니다.

'Before "'"$SearchTerm"'" After'실제로는 세 개의 문자열이 연결되어 있습니다.

'Before "'# 마지막으로 큰따옴표 뒤에 작은따옴표가 옵니다.

"$SearchTerm"# 여기서 매개변수 확장이 발생합니다.

'" After' # 작은따옴표로 시작하고 그 뒤에 큰따옴표가 옵니다.

더 명확해지기를 바랍니다.

답변2

호출하는 인라인 스크립트는 작은따옴표로 묶어야 합니다. 이것은 sh -c쉘이 확장되지 않은 스크립트를 얻게 된다는 것을 의미합니다 "${SearchTerm}". 쉘에는 변수가 없으므로 SearchTerm해당 값은 비어 있습니다.

질문에 태그를 지정했기 때문에, 내보낸 함수의 이름을 전달할 수 있습니다.

# 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

testfunc=${1:-:}코드에서 사용 가능하고 비어 있지 않으면 할당되고 $1, 그렇지 않으면 테스트(true를 반환하는 무작동 유틸리티) testfunc로 사용됩니다 .:

답변3

그냥 실행하는 대신 임의의 셸 코드를 실행할 수 있는 몇 가지 대안은 다음과 같습니다 [ -f "$d/${d##*/}.md" ].

셸 코드는 첫 번째 인수로 전달되어 eval이를 해석하는 데 사용됩니다.

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

환경변수와 동일

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

해석할 쉘 코드가 항상 다음과 같은 경우 [ -f "something" ]:

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

를 사용하는 경우 glob 한정자 ( ) zsh만 사용하여 임의의 셸 표현식으로 디렉터리를 추가로 한정할 수 있습니다 .e/e

print -rC1 ./**/*(ND/e['[ -f $REPLY/$REPLY:t.md ]'])

또는 다음 기능을 사용하세요.

has_md() [ -f $REPLY/$REPLY:t.md ]
print -rC1 ./**/*(ND/+has_md)

( Nfor nullglob, Dfor 는 dotglob숨겨진 파일과 디렉토리를 무시하지 않습니다)

관련 정보