쉘 변수를 사용하여 명령 실행

쉘 변수를 사용하여 명령 실행

변수에 unix 명령이 있는데 다음과 같습니다.

cmd="find /path/to/webpage -type f | grep -v .svn | xargs grep $@"
`$cmd`
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]

$cmdBash 스크립트에서 명령을 실행 하려고 하면 작동하지 않습니다. 그러나 똑같은 명령을 복사하여 붙여넣으면 작동합니다. 내가 뭘 잘못하고 있는지 알려주실 수 있나요?

경로 주위에 따옴표를 넣으려고 시도했지만 동일한 오류가 발생했습니다.

cmd="find \"/path/to/webpage\" -type f | grep -v .svn | xargs grep $@"
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]

매개변수를 제거하면 -type f다음 오류가 발생합니다.

cmd="find /path/to/webpage | grep -v .svn | xargs grep $@"
find: invalid predicate `-v'

이로 인해 파이프가 인식되지 않는 것 같습니다. 작동하게 하려면 어떻게 해야 하나요?

답변1

다른 사람들은 그것을 수행하는 방법을 설명했습니다. 여기서 무슨 일이 일어나고 있는지 설명하겠습니다. |변수가 확장되면 파이프 문자는 파이프를 형성하지 않고 리터럴 문자로 작동합니다. 따라서 find다음 매개변수를 사용하여 실행하십시오.

{"/path/to/webpage", "-type", "f", "|", "grep", "-v", ".svn", "|", ...}

를 경로로 해석 |하고 표현식( -type f) 앞에 나타나야 한다고 불평합니다.

`$cmd`또 다른 큰 실수는 그것을 유일한 명령줄 로 사용한다는 것입니다 . $cmd(즉 find ...) 성공하고 유사한 출력을 생성 하면 rm -rf /사용자를 대신하여 실행됩니다.데이터를 코드로 취급할 때는 주의하세요!

개선 1. find ... | grep -v ...출력에서 무언가를 제외하는 나쁜 방법입니다. find이름이 지정된 전체 하위 디렉토리를 탐색하고 .svn행이 생성되지만 나중에 삭제됩니다. 그냥 나 find한테 하라고 하면 안 될까 ?

find path -type f | grep -v .svn                # don't do this
find path -name .svn -prune -o -type f -print   # do this instead

개선 2.findand 를 결합할 때는 xargs항상 -print0in find-0in 을 사용하세요 xargs.

find path ... -print0 | xargs -0 -r grep ...    # I'd also recommend -r

아니면 정확히 이렇게 할 수도 있습니다 grep:

grep --recursive --exclude-dir=.svn pattern path

답변2

실제로 변수에서 코드를 실행하려면 를 사용할 수 있습니다 eval.

cmd="find /path/to/webpage -type f | grep -v .svn | xargs grep something"
eval "$cmd"

하지만 with 에 인수를 전달하려고 하므로 $@필요한 것은 함수입니다.

webgrep() {
    find /path/to/webpage -type f | grep -v .svn | xargs grep "$@"
}

공백 문자가 포함된 모든 경로에 문제가 발생한다는 점에 유의하세요. 또는 빼기 기호로 시작하는 패턴입니다. .svn디렉터리를 무시하기 전에 디렉터리의 전체 내용을 검사해야 합니다. 사용자가 실수로 여러 매개변수를 전달하는 경우(예: 스키마가 올바르게 인용되지 않은 경우)를 처리하는 것이 좋을 것입니다. 더 좋은 방법은

webgrep() {
    find /path/to/webpage -name .svn -prune -o -type f -exec grep -e "$*" {} +
}

그런 다음 이렇게 부르세요

webgrep PATTERN

답변3

다음과 같이 변수를 만들어 보세요.

cmd=$(find /path/to/webpage -type f | grep -v .svn | xargs grep $@)

또는

cmd=`find /path/to/webpage -type f | grep -v .svn | xargs grep $@`

또는 별칭이 더 적합할 수도 있습니다.

alias cmd="find /path/to/webpage -type f | grep -v .svn | xargs grep $@"

답변4

아니요경험상 코드를 변수에 넣으세요. 기능을 사용하세요.

cmd() { 
  find /path/to/webpage -type f |
    grep -v .svn                | 
    xargs grep $@
}

cmd "$@"

결국 넣어야 한다면단순한코드는 변수에 있습니다(그렇지 않지만 그렇게 한다면...). 위에서 언급한 대로 파이프 같은 것을 삽입하거나 eval... 없이 리디렉션할 수 없습니다. 그것도 하지 마세요, 하하

그러나 하위 쉘에서 명령을 실행하고 이를 출력으로 바꾸는 백틱 내에서 실행하지 마십시오. 그러면 출력은 파서가 실행 명령으로 수신하는 것이 됩니다.

$: `echo foo`
bash: foo: command not found

관련 정보