나는 이 코드를 가지고 있습니다 :
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=omsssi
hostport=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/' )" \
이는 두 개의 매개변수를 설정합니다. 하나는 -e
sed에 필요한 문자열이고 다른 하나는 매개변수입니다.
편집된 스크립트:
#!/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