xargs: 각 줄에 대해 명령을 실행하고 인수를 공백으로 구분하시겠습니까?

xargs: 각 줄에 대해 명령을 실행하고 인수를 공백으로 구분하시겠습니까?

wsl.exe를 사용하여 cygwin bash 및 oh-my-zsh에서 이 문제를 재현할 수 있습니다. 내 의도는 명령줄에서 다음 두 줄을 실행하는 것입니다.

npm rm plugin-alias
npm i -D plugin-alias

나는 이것을하려고 노력하고 있습니다 :

echo -ne "rm\0i -D\0" | xargs -t -0 -IREPLACE npm REPLACE plugin-alias

잘 달리고 있어요 rm. -t실행 중이라고 합니다 npm rm plugin-alias. 하지만 i -D오류:

npm 'i -D' plugin-alias
Unknown command: "i -D"

i -Dxargs가 여러 인수로 전달되어 실행되도록 하는 방법이 있습니까 npm i -D plugin-alias?

,구분 기호를 and 로 변경해 보았지만 \n차이가 없는 것 같습니다.

따옴표를 제거 해야 한다면 sed그렇게 하십시오. 하지만 xargs이로 인해 발생하는 문제가 해결되기를 바랍니다.


업데이트: @muru가 유용한 의견을 제공했습니다.

@muru: 실제 인용문은 포함되어 있지 않습니다.

나: 그러면 왜 알 수 없는 명령: "i -D"라는 오류 메시지가 표시되나요?

@muru: xargs는 i -D를 다음과 같이 제공하기 때문입니다.단일 인수npm으로.

이제 이해했으므로 제목을 더 정확하게 편집할 수 있습니다. 더 나은 검색 가능성을 위해 원래 제목은 "xargs가 공백이 있는 항목을 인용하는 이유와 이를 방지하는 방법은 무엇입니까?"였습니다.

답변1

답변:

xargs: 각 줄에 대해 명령을 실행하고 인수를 공백으로 구분하시겠습니까?

테마에서 이것이 바로 -L¹ 옵션이 사용되는 용도입니다.

xargs -L1 cmd << 'EOF'
1 2 3
first 'second arg'
"a 1" b\
2
EOF

cmd각각 실행됩니다1 L이네입력(논리적 줄, 두 번째 매개변수에 포함된 개행 문자를 인용하고 후행 공백을 사용하면 긴 줄을 나눌 수 있으므로 세 번째 줄은 두 개의 물리적 줄로 구성되어 있음을 알 수 있습니다), 각 줄을 다음으로 분할합니다. 논쟁을 중심으로.

-I그러나 GNU 스타일과 결합할 수는 없습니다 -0.

이것은 어떤 형태의 인용을 이해하기 때문에(구문은 현대 쉘의 구문과 다르다는 점에 유의하세요) 임의의 인수를 지정할 수 있도록 허용하므로(제한사항은 구현에 따라 다름²) -0.

BSD의 경우 xargswhile과 결합하여 -J다음을 수행할 수 있습니다.

xargs -rL1 -J {} npm {} plugin-alias << 'EOF'
rm
i -D
EOF

다른 구현의 경우 다음을 사용하여 sh매개변수 순서를 변경할 수 있습니다.

xargs -L1 sh -c '[ "$#" -eq 0 ] || exec npm "$@" plugin-alias' sh << 'EOF'
rm
i -D
EOF

(여기서는 [ "$#" -eq 0 ] ||비표준 대체품 으로도 사용됩니다 -r).


1 GNU xargs에는 더 이상 사용 되지 -l않는 비표준 가 하나 이상 있습니다 -L 1. -l예를 들어 와 같이 여러 줄을 사용할 수도 있지만 ; 대신 -L옵션에 추가해야 합니다. 또는 ).-l1-l 1-L1-L 1

² 예를 들어, 일부는 텍스트가 아닌 입력을 방해하고, 일부는 명령줄 길이 또는 개별 인수에 대한 제한이 극히 낮으며, 일부는 _파일 끝을 이해합니다... 또한 구분 기호로 인식되는 문자 목록은 다음에 따라 다릅니다. 일부의 구현 및 로케일 설정.

답변2

일반적으로 사용을 권장하지 않습니다. 이에 대해 셸의 토큰화를 적용할 수 있습니다.

printf "rm\0i -D\0" | 
   xargs -t -0 -I{} sh -f -c 'npm $1 plugin-alias' sh {}  

sh여기서는 NUL로 구분된 각 문자열을 단일 인수로 스크립트 에 전달하고 있으며 , 따옴표 없이 확장 $1하면 공백으로 분할됩니다. 옵션 -f(에 대한 set -f)은 와일드카드를 비활성화합니다.

스크립트를 사용하여 다양한 명령줄 매개변수를 명확하게 확인하세요.

% printf "rm\0i -D\0" | 
   xargs -t -0 -I{} sh -f -c './args.sh npm $1 plugin-alias' sh {}
sh -f -c ./args.sh npm $1 plugin-alias sh rm
3 args: <npm> <rm> <plugin-alias> 
sh -f -c ./args.sh npm $1 plugin-alias sh i -D
4 args: <npm> <i> <-D> <plugin-alias> 

또는 -LNUL 구분 기호를 개행 문자로 변경하면 원하는 대로 할 수 있다고 생각합니다. 그러나 -I공백 분할이 비활성화된 것처럼 보이기 때문에 올바른 순서로 인수를 얻으려면 여전히 셸이 필요한 것 같습니다 .

% printf 'rm\ni -D\n' |xargs -L1 sh -c './args.sh npm "$@" plugin-alias' sh  
3 args: <npm> <rm> <plugin-alias> 
4 args: <npm> <i> <-D> <plugin-alias> 

어쨌든 버전 간에 차이가 있는지는 잘 모르겠지만 xargs쉘을 사용하여 동일한 작업을 수행할 수 있습니다.

$ printf 'rm\ni -D\n' | while read -r line ; do set -f; ./args.sh npm $line plugin-alias; done
3 args: <npm> <rm> <plugin-alias> 
3 args: <npm> <i -D> <plugin-alias> 

args.sh이 스크립트는 다음과 같습니다.

#!/bin/sh
if [ "$#" != 0 ]; then
    printf "%d args: " "$#"
    printf "<%s> " "$@"
    echo
else
    printf "no args.\n"
fi

답변3

xargs여기서는 를 사용하는 대신 쉘이 목록을 읽도록 할 수 있습니다. 그리고 zsh:

while IFS=, read -rd '' -u3 -A args; do
  npm "$args[@]" plugin-alias
done 3< <(printf '%s\0' rm i,-D)

,빈 매개변수를 더 쉽게 지정할 수 있도록 여기에서 매개변수를 구분합니다 .

이것은 표시하려는 목록의 목록입니다. 외부 명령에 대한 임의 인수의 단일 목록은 NUL 문자로 구분하여 표시할 수 있습니다. 명령 인수에는 NUL 문자를 포함할 수 없다는 제한이 있기 때문입니다(bash 내장 및 함수에 대한 인수에는 동일한 제한이 있지만 zsh의 인수에는 적용되지 않음). ), 그러나 임의의 요소 목록을 나타내려면 단일 구분 기호에 의존할 수 없으며 특정 형식의 인코딩을 사용해야 합니다.

read한 가지 옵션은 없이 사용하는 것입니다 -r. 예를 들어 위 옵션을 제거하면 -r2개의 목록을 나타낼 수 있습니다. 첫 번째 목록에는 빈 문자열이 포함되고 foo,bar두 번째 목록에는 줄 바꿈 및 백슬래시가 포함됩니다.

printf '%s\0' ',foo\,bar' '
,\\'

,\에 있는 동안 접두사를 기억해야 합니다 \.

에서는 zsh빈 레코드가 빈 요소로 분할됩니다. Bash 또는 ksh에는 요소가 전혀 없으며 2개의 레코드 와 빈 요소 foo,로 분할됩니다 . foo또한 를 로 대체 bash해야 합니다 .-a-A

관련 정보