예:
% touch -- safe-name -name-with-dash-prefix "name with space" \
'name-with-double-quote"' "name-with-single-quote'" \
'name-with-backslash\'
xargs
큰따옴표를 처리할 수 없는 것 같습니다.
% ls | xargs ls -l
xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option
ls: invalid option -- 'e'
Try 'ls --help' for more information.
해당 옵션을 사용하면 -0
이름 앞에 대시가 붙으면 문제가 발생합니다.
% ls -- * | xargs -0 -- ls -l --
ls: invalid option -- 'e'
Try 'ls --help' for more information.
개행 문자, 제어 문자 등과 같이 잠재적으로 문제가 있는 다른 문자를 사용하기 전입니다.
답변1
이것POSIX 사양당신에게 예를 제공합니다 :
ls | sed -e 's/"/"\\""/g' -e 's/.*/"&"/' | xargs -E '' printf '<%s>\n'
(파일 이름은 임의의 순서입니다.바이트( /
NULL 제외) 및 sed
/ xargs
기대텍스트, 신뢰할 수 있도록 로케일을 C(NUL이 아닌 모든 바이트가 유효한 문자를 생성하는 경우)로 수정해야 합니다( xargs
인수 최대 길이에 대한 제한이 매우 낮은 구현 제외).
-E ''
일부 구현에서는 입력의 끝(예: 출력만) 을 나타내는 인수를 xargs
이해해야 합니다 ._
echo a _ b | xargs
a
GNU를 사용하면 xargs
다음을 사용할 수 있습니다.
ls | xargs -rd '\n' printf '<%s>\n'
(또한 추가된 -r
(또한 GNU 확장)은 입력이 비어 있으면 명령이 실행되지 않는다는 것입니다.)
GNU에는 다른 구현에 의해 복사된 xargs
것도 있으므로 다음과 같습니다.-0
ls | tr '\n' '\0' | xargs -0 printf '<%s>\n'
휴대성이 조금 더 좋아졌습니다.
이 모든 것은 파일 이름에 개행 문자가 포함되어 있지 않다고 가정합니다. 파일 이름에 줄 바꿈이 있을 수 있는 경우 출력은 ls
전혀 사후 처리되지 않습니다. 당신이 얻는 경우:
a
b
이것은 a
and b
파일일 수도 있고 이름이 이라는 파일일 수도 있습니다 a<newline>b
. 알 수 있는 방법이 없습니다.
GNU에는 출력을 명확하게 만들고 사후 처리할 수 있는 ls
기능이 있지만 인용은 예상 인용과 호환되지 않습니다 . 식별 및 인용 양식 . 그러나 and 는 둘 다 강한 따옴표이고 개행 문자를 포함할 수 없습니다( 개행 문자만 이스케이프할 수 있음 ). 따라서 강한 따옴표만 있고 개행 문자를 포함할 수 있지만 이스케이프 대신 줄 연속(제거)이 있는 sh 따옴표와 호환 되지 않습니다. 개행 문자.--quoting-style=shell-always
xargs
xargs
"..."
\x
'...'
"..."
'...'
\
xargs
'...'
\<newline>
셸을 사용하여 이 출력을 구문 분석하고 예상 형식으로 출력할 수 있습니다 xargs
.
eval "files=($(ls --quoting-style=shell-always))"
[ "${#files[@]}" -eq 0 ] || printf '%s\0' "${files[@]}" |
xargs -0 printf '<%s>\n'
또는 쉘이 파일 목록을 가져오고 NUL로 구분하여 전달하도록 할 수 있습니다 xargs
. 예를 들면 다음과 같습니다.
그리고
zsh
:print -rNC1 -- *(N) | xargs -r0 printf '<%s>\n'
그리고
ksh93
:(set -- ~(N)*; (($# == 0)) || printf '%s\0' "$@") | xargs -r0 printf '<%s>\n'
그리고
fish
:begin set -l files *; string join0 -- $files; end | xargs -r0 printf '<%s>\n'
그리고
bash
:( shopt -s nullglob set -- * (($# == 0)) || printf '%s\0' "$@" ) | xargs -r0 printf '<%s>\n'
2023년 편집. GNU coreutils 버전 9.0(2021년 9월)부터 GNU에는 ls
이제 --zero
다음 명령과 함께 사용할 수 있는 옵션이 있습니다 xargs -r0
.
ls --zero | xargs -r0 printf '<%s>\n'
답변2
xargs
null로 구분된 입력 옵션을 이해 하려면 -0
보낸 사람은 보내는 데이터에 null 구분 기호도 적용해야 합니다.
그렇지 않으면 둘 사이에 동기화가 발생하지 않습니다.
한 가지 옵션은 GNU find
이러한 구분 기호를 배치할 수 있는 명령입니다.
find . -maxdepth 1 ! -name . -print0 | xargs -0 ls -ld
답변3
말씀하신 대로 xargs
를 사용하지 않는 한 일치하지 않는 큰따옴표를 좋아하지 마세요. -0
하지만 -0
이는 null로 끝나는 데이터를 입력하는 경우에만 의미가 있습니다. 따라서 이것은 실패합니다.
$ echo * | xargs
xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option
name-with-backslash -name-with-dash-prefix
하지만 이것은 작동합니다:
$ printf '%s\0' -- * | xargs -0
-- name-with-backslash\ -name-with-dash-prefix name-with-double-quote" name-with-single-quote' name with space safe-name
어쨌든 기본 접근 방식은 실제로 이 작업을 수행하는 가장 좋은 방법은 아닙니다. xargs
and 및 ls
이와 같은 것들을 조작하는 대신 쉘 glob을 사용하십시오.
$ for f in *; do ls -l -- "$f"; done
-rw-r--r-- 1 terdon terdon 4142 Aug 11 16:03 a
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name-with-backslash\'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 -name-with-dash-prefix
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name-with-double-quote"'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 "name-with-single-quote'"
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 'name with space'
-rw-r--r-- 1 terdon terdon 0 Aug 11 15:34 safe-name
답변4
이것을 시도하는 것은 매우 어리석은 일입니다명령의 출력을 구문 분석합니다.ls
그건구문 분석용으로 설계되지 않음명령을 내리다여러 문자를 처리하는 데 적합하지 않음(예: new lines
및 {}
) 쉘이 자체적으로 이 작업을 수행하는 경우:
set -- *; for f; do echo "<$f>"; done
set -- *
for f
do ls "$f"
done
또는 명령줄에서 다음을 수행합니다.
$ set -- *; for f; do echo "<$f>"; done
<name-with-backslash\>
<-name-with-dash-prefix>
<name-with-double-quote">
<name-with-single-quote'>
<name with space>
<safe-name>
<with_a
newline>
출력 처리(그리고 마지막 파일 이름으로 n 개의 예제를 갖는 것)는 개행에 전혀 문제가 없다는 점에 유의하십시오.
또는 파일 개수로 인해 셸 속도가 느려지는 경우 find를 사용하세요.
$ find ./ -type f -exec echo '<{}>' \;
<./safe-name>
<./with_a
newline>
<./name-with-double-quote">
<./-name-with-dash-prefix>
<./name with space>
<./name-with-single-quote'>
<./name-with-backslash\>
find는 쉘과 다르게 모든 도트 파일과 모든 하위 디렉터리를 처리합니다.