루프의 특수 문자가 다른 명령의 인수로 이스케이프되는 것을 방지하는 방법은 무엇입니까?

루프의 특수 문자가 다른 명령의 인수로 이스케이프되는 것을 방지하는 방법은 무엇입니까?

내 입력 파일(objects.lst)은 다음과 같습니다.

host.fqdn.com:/ 'host.fqdn.com [/]'
host.fqdn.com:/boot 'host.fqdn.com [/boot]'
host.fqdn.com:/tmp 'host.fqdn.com [/tmp]'
host.fqdn.com:/tmp '/tmp'
host.fqdn.com:/ '/usr/share'
host.fqdn.com:/var 'host.fqdn.com [/var]'

이 파일을 한 줄씩 반복하고 싶고 각 줄이 타사 소프트웨어에 대한 인수로 필요합니다.

그래서 나는 다음과 같은 것을 시도했습니다.

#!/bin/bash
set -x
while read -r line; do
/opt/report -filesystem "$line" -detail
done < objects.lst

이것은 다음과 같이 해석될 것이다.

 /opt/report -filesystem 'host.fqdn.com:/ '\''host.fqdn.com [/]'\''' -detail

하지만 그래야 해

/opt/report -filesystem host.fqdn.com:/ 'host.fqdn.com [/]'

매개 변수를 배열, 변수, 다양한 참조에 저장하고 for 루프를 통해 저장하는 등 다양한 작업을 시도했지만 echo -E원하는 방식으로 작동하는 것은 없습니다.

현재 해결 방법은 다음과 같습니다.

#!/bin/bash
set -x
while read -r line; do
echo "/opt/report -filesystem "${line}" -detail" | bash -
done < objects.lst

bash에 에코/파이핑하지 않고 작동하게 하는 또 다른 방법이 있습니까?

${parameter@Q}(bash 4.4에서 사용 가능)의 몇 가지 예를 보았지만 bash 4.2를 사용하고 있습니다.

분명히 set -x 출력을 혼동했지만 문제는 여전히 동일합니다. 저는 object.lst를 반복하고 있으며 object.lst와 정확히 동일한 전체 행이 매개변수로 필요합니다.

따라서 아래 설명을 올바르게 이해하면 다음과 같습니다.

while read -r line; do
/opt/report -filesystem "$line" -detail
done < objects.lst

이는 정확히 다음과 같아야 합니다.

/opt/report -filesystem host.fqdn.com:/ 'host.fqdn.com [/]'

그러나 그것은 진실이 아니다. 루프에서 omnidb/report에서 "객체를 찾을 수 없음"이 발생하기 때문에 타사 소프트웨어가 여기서 문제일 수 있습니다(microfocus data saver/omnidb cli 명령).

하지만 내가 만들면

while read -r line; do
echo "/opt/report -filesystem "$line" -detail"
done < objects.lst

출력 명령에서 복사/붙여넣기를 하면 정상적으로 작동하고 omnidb/report 명령에서 올바른 개체 정보를 인쇄합니다.

답변1

의 경우 /opt/report -filesystem "$line" -detail다음 host.fqdn.com:/ 'host.fqdn.com [/]'과 같이 그대로 전달됩니다.하나명령의 인수와 set -x출력은 값을 작은따옴표(셸에서는 리터럴 따옴표)로 표시하여 이를 알려줍니다.

존재하다

/opt/report -filesystem host.fqdn.com:/ 'host.fqdn.com [/]'

명령에 두 개의 인수( host.fqdn.com:/및 ) 를 전달합니다 host.fqdn.com [/]. 이는 공백 문자와 작은따옴표 문자가 모두 쉘 구문에서 특별하기 때문입니다.

쉘의 경우 위에 '...'표시된 대로말 그대로따옴표는 문자 그대로 텍스트를 전달하는 데 사용되며 내부 문자는 특별히 처리되지 않으며 셸 구문의 SPC(자체가 따옴표로 묶이지 않은 경우)는 인수(또는 보다 일반적으로 셸 구문의 토큰)를 구분하는 데 사용됩니다.

host.fqdn.com:/ 'host.fqdn.com [/]'출력에 표시된 대로 문자 그대로 인수로 전달 하려면 set -x다음과 같은 것이 필요합니다 'host.fqdn.com:/ '\''host.fqdn.com [/]'\'''. 단, 다른 유형의 따옴표를 사용해 "host.fqdn.com:/ 'host.fqdn.com [/]'"도 작동합니다.

$ printf '<%s>\n' 'host.fqdn.com:/ '\''host.fqdn.com [/]'\'''
<host.fqdn.com:/ 'host.fqdn.com [/]'>
$ printf '<%s>\n' "host.fqdn.com:/ 'host.fqdn.com [/]'"
<host.fqdn.com:/ 'host.fqdn.com [/]'>

이것을 명령에 전달된 리터럴 인수가 아닌 쉘 코드로 해석 해야 하는 경우 파이프와 같은 것에서 쉘 인터프리터를 호출 host.fqdn.com:/ 'host.fqdn.com [/]'해야 합니다 (큰따옴표 사용은 올바르지 않지만) .$linebasheval

#!/bin/bash -
set -x
while IFS= read -r line; do
  eval "/opt/report -filesystem $line -detail"
done < objects.lst

그러나 이는 행에 ;reboot;또는 이 포함되어 있으면 $(reboot)명령 reboot이 호출된다는 것을 의미합니다.

다른 부작용(예: 위 명령 실행) 없이 쉘 토큰화 및 참조 제거를 수행하려는 경우 연산자와 함께 명령을 reboot사용할 수 있습니다 .zsh

#!/bin/zsh -
set -x
while IFS= read -r line; do
  /opt/report -filesystem "${(Q@)${(z)line}}" -detail
done < objects.lst

이로 z인해 토큰화가 zsh코드가 되고 Q따옴표 레이어가 제거됩니다. 예를 들어, 다음과 같은 줄에서:

foo 'bar baz' $(echo x y)

foo, bar baz및 3개의 매개변수를 전달합니다 $(echo x y).

답변2

작성한 내용에 따르면 해당 행을 단일 인수로 프로그램에 전달할 필요는 없지만 두 개의 인수로 전달할 필요가 있는 것 같습니다. 행에서 인용되지 않은 부분을 하나로, 다음 인용 문자열을 다른 인수로 전달합니다. .

만약에이 모든 줄은 이 형식을 따릅니다(더 이상 인용된 문자열이 포함된 줄은 없습니다). Bash에서 다음과 같은 작업을 수행할 수 있습니다.

#/bin/bash
while IFS=" " read -r a b; do
    b=${b%\'};
    b=${b#\'};
    /opt/report -filesystem "$a" "$b" -detail
done < objects.lst

첫 번째 공간에서 라인을 두 부분으로 나누고 그 부분을 sum read에 저장합니다 . 그런 다음 작은따옴표가 제거되고 두 문자열이 모두 다른 인수로 에 전달됩니다 .abb=${b%\'}; b=${b#\'};/opt/report

관련 정보