쉘 변수 테스트 확장 문제

쉘 변수 테스트 확장 문제

나는 이 코드를 가지고 있습니다 :

sed \
$( (( $compress == 1 )) && echo -n '-e /^RMTHOST/ s/$/, compress/' ) \
-e "s|\*\*jobname\*\*|$jobname|g" \
-e "s|\*\*hostname\*\*|$hostname|g" \
-e "s|\*\*hostport\*\*|$hostport|g" \
-e "s|\*\*rmttrailname\*\*|$rmttrailname|g" < $GGPARAMSDIR/pump.template > 
$GGPARAMSDIR/$jobname.prm

이것은 내가 원하는 대로 거의 작동합니다. 그렇다면 문자열이 포함되기를 $compress == 1원합니다 . 이면 이 부분은 포함되지 않습니다.sed-e /^RMTHOST/ s/$/, compress/'$compress != 1

다음과 같은 오류가 발생하면$compress is 1

 sed: -e expression #1, char 10: missing command

디버깅을 위해 스크립트에 set -x를 추가하면 다음과 같이 확장됩니다.

sed -e '/^RMTHOST/' 's/$/,' compress/ -e 's|\*\*jobname\*\*|pssic|g' -e 's|\*\*hostname\*\*|omsssi|g' -e 's|\*\*hostport\*\*|7809|g' -e 's|\*\*rmttrailname\*\*|./dirdat/dsn/rc|g'

단일 틱이 -e첫 번째 표현식을 닫는다는 점에 유의하십시오 /^RMTHOST/. 이것이 내 문제를 일으키는 것이라고 확신합니다. 하지만 문제를 해결하기 위한 구문을 알 수 없습니다.

참고로 변수의 값 은 jobname=pssic,hostname=omsssihostport=7809

누구든지 도와줄 수 있나요?

답변1

질문

문제는 명령 대체 결과가 경로 이름 확장 및 단어 분리의 영향을 받는다는 것입니다.

명령 대체의 출력에 어떤 일이 발생하는지 확인하기 위해 이를 사용하여 printf생성된 단어를 표시해 보겠습니다.

$ printf ">%s<\n" $( (( compress == 1 )) && echo -n '-e /^RMTHOST/ s/$/, compress/' )
>-e<
>/^RMTHOST/<
>s/$/,<
>compress/<

정말 -e별도의 단어가 필요합니다. 그러나 단어 분리로 인해 sed 대체 명령이 sed가 실행할 명령으로 분할될 수도 있습니다.아니요이해하다:

$ sed -e '/^RMTHOST/' 's/$/,' 'compress/'
sed: -e expression #1, char 10: missing command

해결책

대신 bash 배열을 사용해 보세요:

#!/bin/bash
jobname=pssic
hostname=omsssi
hostport=7809
compress=1
rmttrailname=SomethingElse

args=()
(( compress == 1 )) && args+=('-e' '/^RMTHOST/ s/$/, compress/')
args+=(
    -e "s|\*\*jobname\*\*|$jobname|g"
    -e "s|\*\*hostname\*\*|$hostname|g"
    -e "s|\*\*hostport\*\*|$hostport|g"
    -e "s|\*\*rmttrailname\*\*|$rmttrailname|g"
    )

declare -p args  # Optional: Verify the args are what we want.

sed "${args[@]}" <"$GGPARAMSDIR/pump.template" >"$GGPARAMSDIR/$jobname.prm"

잘 읽었습니다

쉘 변수에서 명령을 생성하는 문제에 대한 흥미롭고 보다 일반적인 토론은 다음과 같습니다."명령을 변수에 넣으려고 하는데 복잡한 경우가 항상 실패합니다!"

답변2

POSIX 솔루션:

인용없이명령 대체는 단어 분리의 영향을 받습니다.

변화:

$( (( $compress == 1 )) && echo -n '-e /^RMTHOST/ s/$/, compress/' ) \

받는 사람(인용 확장자):

-e "$( [ "$compress" -eq 1 ] && printf '%s' '/^RMTHOST/ s/$/, compress/' )" \

이는 두 개의 매개변수를 설정합니다. 하나는 -esed에 필요한 문자열이고 다른 하나는 매개변수입니다.

편집된 스크립트:

#!/bin/sh

compress=$1
jobname=pssic
hostname=omsssi
hostport=7809
rmttrailname=ends
#set -x
echo "RMTHOST **jobname** **hostname** **hostport** **rmttrailname** test" | \
    sed \
    -e "$( [ "$compress" -eq 1 ] && printf '%s' '/^RMTHOST/ s/$/, compress/' )" \
    -e "s|\*\*jobname\*\*|$jobname|g" \
    -e "s|\*\*hostname\*\*|$hostname|g" \
    -e "s|\*\*hostport\*\*|$hostport|g" \
    -e "s|\*\*rmttrailname\*\*|$rmttrailname|g"
#set +x

그리고 코드를 테스트합니다( 없이 set -x).

$  ./so 1
RMTHOST pssic omsssi 7809 ends test, compress

set -x가 주석 처리되지 않은 경우:

$ ./so 1
+ echo RMTHOST **jobname** **hostname** **hostport** **rmttrailname** test
+ [ 1 -eq 1 ]
+ printf %s /^RMTHOST/ s/$/, compress/
+ sed -e /^RMTHOST/ s/$/, compress/ -e s|\*\*jobname\*\*|pssic|g -e s|\*\*hostname\*\*|omsssi|g -e s|\*\*hostport\*\*|7809|g -e s|\*\*rmttrailname\*\*|ends|g
RMTHOST pssic omsssi 7809 ends test, compress
+ set +x

배열을 사용하는 쉘

완전히 다른 접근 방식(및 모범 사례)은 모든 인수를 배열(배열이 있는 셸만)에 누적하는 것입니다.

#!/bin/bash
compress=$1
jobname=pssic
hostname=omsssi
hostport=7809
rmttrailname=ends

args=()
(( compress == 1 )) && args+=('-e' '/^RMTHOST/ s/$/, compress/')
args+=( -e "s|\*\*jobname\*\*|$jobname|g" )
args+=( -e "s|\*\*hostname\*\*|$hostname|g" )
args+=( -e "s|\*\*hostport\*\*|$hostport|g" )
args+=( -e "s|\*\*rmttrailname\*\*|$rmttrailname|g" )

echo "RMTHOST **jobname** **hostname** **hostport** **rmttrailname** test" | \
    sed "${args[@]}"

달리기:

$ ./script 1
RMTHOST pssic omsssi 7809 ends test, compress

관련 정보