동적으로 명령 작성


9

스크립트를 작성 중이며 tar명령을 동적으로 작성 해야합니다 .

다음은 내가하려는 일을 설명하는 두 가지 예입니다.

#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "${EXCLUDE[@]}"`" -zcf tmp.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

echo -e "\n\nNEXT:\n\n"

EXCLUDE=("--exclude=/tmp/hello\ hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "${EXCLUDE[@]}"`" -zcf test.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

_tar명령 으로 사용할 수 있기를 원 하지만 클래식 경로에서 작동하도록 만들었지 만 폴더 이름의 공백으로 작동해야합니다. 그리고 매번 다음과 같은 오류가 발생했습니다.

COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*"  -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello\ hello --exclude=/tmp/systemd* --exclude=/tmp/Temp*  -zcf test.tar.gz 
tar: hello: Cannot stat: No such file or directory

당신이 알아야 할 한가지, 아주 오래된 머신에서 작동하려면 스크립트가 필요합니다. 즉, 마지막 bash 기능을 사용할 수 없습니다.


--exclude 옵션은 그 뒤에 단일 문자열 만 허용 할 수 있다고 생각합니다. 그래도 여러 개의 --exclude 문을 가질 수 있습니다. "--exclude = / tmp / hello --exclude = hello"시도해보십시오. 신경 쓰지 마. 나는 오해했다.
Lewis M

@LewisM OP가 "/ tmp / hello hello"디렉토리를 제외하고 싶다고 생각합니다 (예, 공백이 있습니다)
Archemar

@ShellCode 모든 제외를 인용하는 것은 어떻습니까? 예 : "--exclude = / tmp / hello hello"
Archemar

네. 그래서 나중에 Oops 문을 작성했습니다. :)
Lewis M

어떻게 퍼팅에 대한 eval실행의 앞에?
jimmij

답변:


11

실행 가능한 문자열을 만들려고하지 마십시오. 대신 배열에서 인수를 작성하고 호출 할 때 사용하십시오 tar(이미 배열을 올바르게 사용하고 있습니다 EXCLUDE).

#!/bin/bash

directory=/tmp

exclude=( "hello hello" "systemd*" "Temp*" )

# Now build the list of "--exclude" options from the exclude array:
for elem in "${exclude[@]}"; do
    exclude_opts+=( --exclude="$directory/$elem" )
done

# Run tar
tar -cz -f tmp.tar.gz "${exclude_opts[@]}" "$directory"

/bin/sh:

#!/bin/sh

directory=/tmp

set -- "hello hello" "systemd*" "Temp*"

# Now build the list of "--exclude" options from the $@ array
# (overwriting the values in $@ while doing so)
for elem do
    set -- "$@" --exclude="$directory/$elem"
    shift
done

# Run tar
tar -cz -f tmp.tar.gz "$@" "$directory"

의 인용 참고 $@sh코드 모두의 ${exclude[@]}${exclude_opts[@]}bash코드입니다. 이렇게하면 목록이 개별적으로 인용 된 요소로 확장됩니다.

관련 :


2
mix(){
        p=$1; shift; q=$1; shift; c=
        i=1; for a; do c="$c $q \"\${$i}\""; i=$((i+1)); done
        eval "${p%\%*}$c${p#*\%}"
}
mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
mix 'tar % -zcf tmp.tar.gz' --exclude "${EXCLUDE[@]}"

여기 에서 답변을 확장 하십시오 . 이것은 bashism에 의존하지 않으며 debian /bin/sh및 에서도 잘 작동합니다 busybox.


도와 주셔서 감사합니다.하지만 평가판이 마음에 들지 않습니다. 매우 위험합니다 ... 또한이 코드는 이해하기가 어렵습니다. 더 쉬운 것이 없습니까? : / 스크립트는 배포 될 것이므로 가능한 한 간단하게 유지해야합니다 ...
ShellCode

위험하지 않습니다. 로 실행하십시오 set -x. 정확히 이해하지 못하는 것은 무엇입니까?
mosvy

또한 stackoverflow의 원래 답변을 읽으십시오. 데모가 포함되어 있습니다.
mosvy

그것은 꽤 잘 작동합니다 ... 아무도 깨끗한 답변을 가지고 있는지 기다리고, 그렇지 않으면 나는 당신을 받아 들일 것입니다. 어쩌면이 그 코드에 아무 것도 잘못이지만, 내가 평가 후면을 볼 때마다, 나는 내가하려고하는 이유의 그것을 피할 것을, 코드가 명령 주입으로 이어질 수 두려워
쉘 코드

인덱스> 9 수정으로 답을 업데이트했습니다. eval을 에코로 바꾸어 실제로 얻는 것이 무엇인지 볼 수 있습니다 (eval에는 파일 이름이 표시되지 않음)
mosvy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.