Bash 명령 및 변수 대체에 대한 혼란

Bash 명령 및 변수 대체에 대한 혼란

나는 1989년부터 명령줄에서 한 줄짜리 bash 스크립트를 작성해 왔습니다. 이러한 스크립트의 형식은 일반적으로 다음과 같습니다.

for name in 1 2 3; do wc $name.txt; done

이제 저는 두 개의 파일 이름을 매개변수로 사용하는 스크립트를 사용하여 김프를 사용하여 일부 이미지 처리를 수행하려고 합니다. 유효한 명령줄을 제공하는 내용은 다음과 같습니다.

/Applications/GIMP.app/Contents/MacOS/GIMP -b '(script-fu-overlay "png0004.tif" "png0000.tif") (script-fu-overlay "png0004.tif" "png0001.tif") (script-fu-overlay "png0004.tif" "png0002.tif") (script-fu-overlay "png0004.tif" "png0003.tif")'

이는 일반적인 단일 라이너의 도움으로 생성됩니다.

X=\'$(for name in 0 1 2 3; do echo \(script-fu-overlay \"png0004.tif\" \"png000$name.tif\"\) ; done)\'

하지만... 제 질문은 이렇습니다.

echo /Applications/GIMP.app/Contents/MacOS/GIMP -b $X

위의 정확한 명령줄을 제공하지만 실행하면

/Applications/GIMP.app/Contents/MacOS/GIMP -b $X

따옴표가 있는 파일 이름을 열 수 없다는 오류가 발생하지만 실행하면

/Applications/GIMP.app/Contents/MacOS/GIMP -b "$X"

모든 것이 정상입니다. 나의 실제 목표는 변수를 전혀 사용하지 않고 한 줄짜리 명령문을 작성할 수 있는지 확인하는 것입니다. 그것은 다음과 같습니다:

/Applications/GIMP.app/Contents/MacOS/GIMP -b \'$(for name in 0 1 2 3; do echo \(script-fu-overlay \"png0004.tif\" \"png000$name.tif\"\) ; done)\'

하지만 이것은 분명히 같은 방식으로 실패합니다

/Applications/GIMP.app/Contents/MacOS/GIMP -b $X

실패하다.

답변1

예, 쉘 변수를 사용하지 않고 명령줄에서 이 작업을 수행할 수 있습니다.

/Applications/GIMP.app/Contents/MacOS/GIMP -b "$(for name in 0 1 2 3; do echo \(script-fu-overlay \"png0004.tif\" \"png000$name.tif\"\) ; done)"

eval여기서는 작은따옴표를 이스케이프 처리하지 않기 때문에 이스케이프 처리를 해제해야 합니다 . 필요한 유일한 것은 명령이 $(...) 주위의 큰따옴표를 확장하여 단어 분할이 발생하는 것을 방지하고 결과를 인수로 에 전달하는 것입니다 gimp.

답변2

이것은 어떻습니까?

$ /Applications/GIMP.app/Contents/MacOS/GIMP -b \
"$(printf '%s\n' '(script-fu-overlay "png0004.tif" "png'{0..0004}'.png")')"

답변3

man bash설명하다:

확장 순서는 다음과 같습니다. 중괄호 확장, 매개변수 및 변수 확장, 산술 확장, 명령 대체(왼쪽에서 오른쪽으로 수행) 및 경로 이름 확장 [...] 이러한 확장을 수행한 후에는 인용 문자가 나타납니다. 원래 단어에서 자체적으로 인용되지 않은 경우 제거됩니다(인용 제거).

그러므로 그냥 인용해라.원래 단어에서삭제되었습니다. 하지만 귀하의 인용문은 확장 후에만 표시되며 삭제되지 않습니다.

주어진 경우에는 파일 이름에 따옴표가 필요하지 않으므로 이를 유지할 수 있지만 파일 이름에 공백이나 기타 특수 문자가 있으면 문제가 발생합니다. 따옴표나 백슬래시는 이 처리 단계에서 따옴표로 간주되지 않으므로 도움이 되지 않습니다.

"한 단계" 요청을 충족하도록 편집되었습니다.

하지만 공백(예: 및 )이 포함된 파일이 여러 개 있고 foo file foo그 중 일부를 bar file bar원한다면 cat어떻게 해야 할까요 ?

명령줄에 표시됩니다

cat "foo file foo" "bar file bar"

하지만 그 이상이면 스크립트를 작성해야 합니다.

echo -n cat; for name in foo bar; do echo -n \ \"$name file $name\"; done

입력하려는 라인을 정확하게 생성하지만

$(echo -n cat; for name in foo bar; do echo -n \ \"$name file $name\"; done)

위와 같은 이유로 실패하게 됩니다. 모든 것을 큰따옴표로 묶는 것(귀하의 경우에 도움이 됨 gimp)도 작동하지 않습니다. 왜냐하면 새 명령은 단어로 구분해야 하지만 따옴표로 묶어서는 안 되기 때문입니다.

그렇다면 명령줄에 직접 입력하는 것처럼 인용 작업을 수행하려면 어떻게 해야 할까요? 문자열을 셸에 명령으로 전달합니다.

bash -c "$(echo -n cat; for name in foo bar; do echo -n \ \"$name file $name\"; done)"

이는 단일 라인에서 빌드 명령을 실행하는 가장 일반적인 방법입니다.

관련 정보