편집하다:
더 읽기 전에 중요한 참고 사항: 이후코살로난다의 답변, 그가 내가 사용하고 있는 다른 스크립트의 버그를 지적했기 때문에 내 질문은 이제 쓸모가 없습니다. 이 버그는 이제 수정되었으며 제가 설명한 다음 오류는 더 이상 발생하지 않습니다!
$extension의 값이 확장되는 두 가지 문제가 코드에 있습니다.
두 번째 문제는 함수 자체에 있습니다.
긴 이야기 짧게
질문을 쓰기 시작했을 때 막혔지만 효과가 있는 해결책을 찾았습니다.쉘노글로브), 하지만 여전히 "글을 쓸 수 있습니까?"라는 질문이 있습니다.
이 질문에 대한 답이 나왔다고 확신하지만 bash 확장에 관한 수백 가지 주제에 빠져 있습니다.
내 경우는 다음과 같습니다.
- 스크립트를 실행하고 싶습니다(정규식을 허용하는 옵션 패턴을 사용한다고 가정
ffmpeg
).-pattern_type glob -i
*.JPG
- 논쟁하다 (말하자면
*.JPG
) - 변수의 인수(말하자면
$extension
) - 스크립트 매개변수의 변수(말하자면
$1
) - 하지만 나는원하지 않는다기본적으로 쉘이
$extension
유사한 패턴으로 확장되기를 원함*.JPG
이 모든 작업은 스크립트 내에서 발생합니다 script.sh
.
따라서 사용자는 다음을 실행할 수 있습니다.
script.sh 'JPG' ; # where $1='JPG'
참고: 에서는 을 script.sh
연결하여 *.
더 $1
많은 최종 정규식을 얻습니다.*.JPG
나는 (여기서부터) 읽는다https://stackoverflow.com/a/11456496/912046) ffmpeg
인수가 수신되기 전에 쉘 확장이 발생합니다( ffmpeg
쉘 확장이 발생했다는 사실조차 알지 못한 채).
${extension}
나는 따옴표, 큰따옴표 또는 백슬래시를 다양한 방법으로 사용해 보았으나 성공하지 못했습니다.
다음은 몇 가지 시도입니다.
ffmpeg ... "${extension}"
원인: ( ffmpeg 1.jpg 2.jpg [...]
확장 발생)
ffmpeg ... ${extension}
동일한
ffmpeg ... '${extension}'
검색 패턴으로 인해 일치하는 파일이 없습니다 ${extension}
(변수 이름은 문자 그대로 사용됨).
extension="\'${extension}\'" ; # wrapping the single quotes (preventing expansion) directly in variable
ffmpeg ... ${extension}
'*.jpg'
작은따옴표를 포함한 검색 패턴으로 인해 일치하는 파일이 없습니다.
ffmpeg ... \"${extension}\"
동일하지만 검색 중 "*.jpg"
(큰따옴표 포함)
마침내 Shell noglob 옵션을 사용하여 성공했습니다.
다음은 흥미로운 명령입니다.
set -f ; # disable glob (prevent expansion on '*.jpg')
ffmpeg -pattern_type glob -i ${extension} movie.mp4 ;
set +f ; # restore, but what if glob was already disabled? I should not restore it then?
그런데 궁금한데, 구문 분석하려는 변수에서 스크립트 매개변수가 확장되는 것을 방지할 수 있는 다른 방법이 있나요? (그래서 변수가 더 이상 구문 분석/대체되지 않도록 확장을 방지하는 방법(작은따옴표 사용)을 알고 있습니다.)
다음과 같습니다. (하지만 문자열 연결을 읽었습니다. 보안상의 이유로 삽입을 피해야 합니다.)
ffmpeg '${extension}'
|| | 3
|| 2
| 1
어디:
- 1: 최종 결과에 대해 작은따옴표가 켜집니다.
ffmpeg '*.jpg'
- 2:
extension
변수가 주입되고 구문 분석됩니다..jpg
ffmpeg
3: 수동으로 작성한 것처럼 매개변수를 수신하기 위해 작은따옴표를 닫습니다.'*.jpg'
편집: 확장 변수를 할당하는 방법에 대한 설명을 따르세요.
local extension="${2}" ;
echo $extension ;
extension="${extension:=jpg}" ; # Default on "jpg" extension
# wrapp extension type in single quotes + prefix with "*."
extension="*.${extension}" ;
그런 다음 다음과 함께 사용하십시오.
runprintcommand ffmpeg -loglevel verbose -pattern_type glob -i ${extension} "$movieName" ;
runprintcommand
함수/스크립트는 다음과 같습니다 .
function runprintcommand() {
echo "Command to run: (Note: '\\' escape character may not be printed)" ;
echo "$*" ;
$* ;
}
답변1
- 따옴표가 없는 변수는 변수 확장, 단어 분리(기본적으로 공백, 탭 및 줄 바꿈)를 거치며, 생성된 각 단어는 차례로 파일 이름 생성(와일드카드 지정)을 거칩니다.
- 큰따옴표로 묶인 변수는 값이 확장되지만 쉘은 확장된 값을 토큰화하거나 와일드카드로 표시하지 않습니다.
- 작은따옴표 안의 변수는 전혀 확장되지 않습니다.
예:
$ ls
script.sh
$ var='* *'
$ echo $var
script.sh script.sh
$ echo "$var"
* *
$ echo '$var'
$var
코드에는 의 값이 $extension
포함된 glob 패턴으로 확장되고 glob 패턴이 내부적으로 파일 이름(그 자체의 glob 확장에 그대로 전달하려는 ffmpeg -i
)과 조기에 일치하게 만드는 두 가지 문제가 있습니다.
첫 번째는 함수 호출입니다.
runprintcommand ffmpeg -loglevel verbose -pattern_type glob -i ${extension} "$movieName" ;
여기에는 ${extension}
아무 것도 인용되지 않았으므로정말해당 값에서 발생하는 파일 이름 글로빙을 가져옵니다(토큰화 및).
두 번째 문제는 함수 자체입니다.
function runprintcommand() {
echo "Command to run: (Note: '\\' escape character may not be printed)" ;
echo "$*" ;
$* ;
}
여기서는 함수 호출에서 큰따옴표를 사용 $*
하더라도 다시 (값을 단어로 나눈 다음) 전역을 확장하는 인용되지 않은 부분을 사용하고 있습니다 .${extension}
$*
"$@"
bare 대신 (큰따옴표 포함)을 사용하세요 . 이는 다음으로 확장됩니다.혼자 인용함수의 위치 매개변수입니다.
"$@"
이것이 와 의 차이점입니다 "$*"
:
"$*"
예작은따옴표로 묶인 문자열. 이는 일반적으로 매개변수가 있는 명령을 실행하는 데 사용할 수 없습니다."$@"
예큰따옴표로 묶인 단어 목록. 매개변수를 사용하여 명령을 실행하는 데 사용할 수 있습니다.
답변2
쉘 글로빙을 방지하는 방법은 변수 확장을 인용하는 것입니다. (또한 일반적으로 원하는 대로 단어 분리를 중지합니다.) 물론 이것이 명령 자체가 구형 패턴을 처리하는 것을 막지는 않습니다. ffmpeg
이를 위해 예를 -i
들어 동일하게 적용됩니다 . find -name
후자를 예로 들어 보겠습니다.
$ touch a.foo b.foo c.bar
$ extension=foo
$ set -x
$ find . -name "*.$extension"
+ find . -name '*.foo'
./b.foo
./a.foo
( +
come from 으로 시작하는 줄은 set -x
명령 셸을 표시합니다.실제로란. )
와일드카드 사용을 중단할 수도 있지만 set -f
단어 분할에는 도움이 되지 않습니다. 변수에 공백이 포함되어 있으면 따옴표가 없는 확장이 중단됩니다 set -f
.
답변3
이를 수행하기 위한 대체 구문을 찾으면 여기에 작성하겠습니다.
플래그를 사용하여 비활성화됨쉘 와일드카드(http://tldp.org/LDP/abs/html/globbingref.html), 확장을 방지합니다.
set -f ; # disable glob (prevent expansion on '*.jpg' to turn in "1.jpg 2.jpg 3.jpg...")
ffmpeg -pattern_type glob -i ${extension} movie.mp4 ;
set +f ; # restore