내가 이해하는 한, 별표 문자는 *
Bash에서 특별한 의미를 가지며, 리터럴 문자를 인쇄하려면 별표를 이스케이프 \*
하거나( ) 인용해야 합니다( "*"
또는 '*'
.
그러나 다음을 시도했을 때 :
$ seq 3 | xargs -I * echo *
1
2
3
*
위의 예에서 Bash가 설명하지 않는 이유는 무엇입니까? 그러나 아래 예에서는 이를 와일드카드로 해석합니다(현재 디렉터리의 파일과 일치).
$ seq 3 | xargs -I* echo * # no space between -I and *
main.py
main.py
main.py
이에 대한 논리를 설명해 주실 수 있나요?
감사해요
답변1
불다했다첫 번째 예에서 별표를 확장합니다.
현재 디렉터리에 파일이 하나만 포함되어 있다고 가정하면 main.py
다음과 같은 일이 발생합니다.
$ seq 3 | xargs -I * echo *
# Expands to:
$ seq 3 | xargs -I main.py echo main.py
echo main.py
이를 위해서는 각 입력에 대해 작업을 수행하고 main.py
해당 입력으로 대체해야 합니다(때문에 -I main.py
). 관찰한 내용은 다음과 같습니다. 세 가지 템플릿이 , 에서 , 으로 echo main.py
변경됩니다 .echo 1
echo 2
echo 3
두 번째 경우에는 단어가 확장되는 것을 방지하기 위해 별표가 바로 옆에 있습니다 -I
(패턴과 일치하는 파일이 없기 때문에 -I*
).
$ seq 3 | xargs -I* echo *
# Expands to:
$ seq 3 | xargs -I* echo main.py
*
이를 위해서는 템플릿의 (리터럴 별표) 인스턴스를 입력으로 바꾸려면 xargs가 필요합니다 . echo main.py
템플릿에는 *
자리 표시자가 전혀 포함되어 있지 않으므로 main.py
매번 인쇄됩니다.
( failglob
Bash에서 활성화하거나 zsh에서 기본 설정을 사용하는 경우 일치하는 항목이 없는 glob은 오류를 생성하고 명령이 실행되지 않습니다.)
명령이 두 가지 발생을 모두 보호하는 경우 *
첫 번째 시도와 동일한 출력을 얻게 됩니다.
$ seq 3 | xargs -I '*' echo '*'
1
2
3
디렉터리에 여러 파일이 있는 경우 인용되지 않은 파일은 *
더 명백한 문제를 일으킬 수 있습니다. 예를 들어, 두 개의 파일이 있고 다음 main.py
과 같은 경우 other.py
:
$ seq 3 | xargs -I * echo *
# Expands to:
$ seq 3 | xargs -I main.py other.py echo main.py other.py
명령으로 실행을 시도합니다 xargs
(현재 입력 문자열로 대체됨). 이로 인해 "명령을 찾을 수 없음" 오류가 발생할 수 있습니다. 또는 정렬 순서의 두 번째 파일 이름이 다음에서 실행 가능한 프로그램과 일치하는 경우other.py echo main.py other.py
main.py
xargs
PATH
xargs
그 프로그램, 설마 echo
.
Bash 확장에서 무슨 일이 일어나고 있는지 어느 정도 가시성을 얻는 데 유용한 방법은 set -o xtrace
. 플래그를 설정한 후 다음으로 시작하는 줄의 확장을 볼 수 있습니다 +
.
$ set -o xtrace
$ seq 3 | xargs -I * echo *
+ seq 3
+ xargs -I main.py echo main.py
1
2
3
$ seq 3 | xargs -I* echo *
+ seq 3
+ xargs '-I*' echo main.py
main.py
main.py
main.py
$ seq 3 | xargs -I '*' echo '*'
+ seq 3
+ xargs -I '*' echo '*'
1
2
3