xargs를 사용하여 이름에 공백과 따옴표가 있는 파일을 복사하려면 어떻게 해야 합니까?

StackOverflow https://stackoverflow.com/questions/143171

문제

디렉터리 아래에 여러 파일을 복사하려고 하는데 많은 파일의 이름에 공백과 작은따옴표가 있습니다.내가 함께 묶으려고 할 때 find 그리고 grep ~와 함께 xargs, 다음 오류가 발생합니다.

find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote

xargs를 보다 강력하게 사용하기 위한 제안 사항이 있습니까?

이게 켜졌어 맥 OS X 10.5.3 (레오파드)와 BSD xargs.

도움이 되었습니까?

해결책

이 모든 것을 단일로 결합 할 수 있습니다 find 명령:

find . -iname "*foobar*" -exec cp -- "{}" ~/foo/bar \;

이렇게하면 공간이있는 파일 이름과 디렉토리를 처리합니다. 당신이 사용할 수있는 -name 사례에 민감한 결과를 얻습니다.

참고 : -- 깃발이 전달되었습니다 cp 파일을 시작하여 시작하는 것을 방지합니다 - 옵션으로.

다른 팁

find . -print0 | grep --null 'FooBar' | xargs -0 ...

나는 여부에 대해 모른다 grep 지원합니다 --null, 또는 여부도 xargs 지원합니다 -0, 레오파드에서, 그러나 GNU에서는 모두 좋습니다.

원래 포스터가 원하는 것을 수행하는 가장 쉬운 방법은 분리기를 모든 공백에서 끝 부분 문자로 바꾸는 것입니다.

find whatever ... | xargs -d "\n" cp -t /var/tmp

"CP"가 여러 번 실행되지 않으므로 더 효율적입니다.

find -name '*FooBar*' -print0 | xargs -0 cp -t ~/foo/bar

나는 같은 문제에 부딪쳤다. 내가 해결 한 방법은 다음과 같습니다.

find . -name '*FoooBar*' | sed 's/.*/"&"/' | xargs cp ~/foo/bar

나는 사용했다 sed 각 입력 라인을 동일한 선으로 대체하지만 이중 인용문으로 둘러싸여 있습니다. 로부터 sed 남자 페이지, "... 교체품에 나타나는 앰퍼 샌드 (``& '')는 re ... 일치하는 문자열로 대체됩니다." -이 경우 .*, 전체 라인.

이것은 해결합니다 xargs: unterminated quote 오류.

이 방법은 작동합니다 Mac OS X V10.7.5 (사자):

find . | grep FooBar | xargs -I{} cp {} ~/foo/bar

또한 게시 한 정확한 구문을 테스트했습니다. 그것은 또한 10.7.5에도 잘 작동했습니다.

사용하지 마십시오 xargs. 깔끔한 프로그램이지만 잘 어울리지 않습니다. find 사소한 사례에 직면했을 때.

다음은 휴대용 (POSIX) 솔루션입니다. find, xargs 또는 cp GNU 특정 확장 :

find . -name "*FooBar*" -exec sh -c 'cp -- "$@" ~/foo/bar' sh {} +

결말에 주목하십시오 + 더 평소 대신 ;.

이 해결책 :

  • 내장 된 공간, 최신 라인 또는 이국적인 캐릭터가있는 파일 및 디렉토리를 올바르게 처리합니다.

  • UNIX 및 Linux 시스템, 심지어 GNU 툴킷을 제공하지 않는 시스템에서도 작동합니다.

  • 사용하지 않습니다 xargs 멋지고 유용한 프로그램이지만 올바르게 처리하기 위해 너무 많은 조정 및 비 표준 기능이 필요합니다. find 산출.

  • 또한 더 효율적입니다 (읽다 더 빠르게) 다른 모든 답변이 아닌 경우 수용된 것보다.

또한 다른 답변이나 의견 인용에 명시된 내용에도 불구하고 {} 이국적인 것을 사용하지 않는 한 쓸모가 없습니다 fish껍데기).

find에서 -print0 옵션을 사용하여 xargs에 -null 명령 선 옵션을 사용하십시오.

찾기 외에 명령에 의존하는 사람들을 위해 ls:

find . | grep "FooBar" | tr \\n \\0 | xargs -0 -I{} cp "{}" ~/foo/bar
find | perl -lne 'print quotemeta' | xargs ls -d

나는 이것이 라인 피드를 제외한 모든 캐릭터에게 안정적으로 효과가 있다고 생각합니다 (그리고 파일 이름에 라인 피드가 있다면 이보다 더 나쁜 문제가 있다고 생각합니다). GNU Findutils가 필요하지 않고 Perl 만 있으므로 어디서나 잘 작동해야합니다.

나는 다음 구문이 나에게 적합하다는 것을 알았습니다.

find /usr/pcapps/ -mount -type f -size +1000000c | perl -lpe ' s{ }{\\ }g ' | xargs ls -l | sort +4nr | head -200

이 예에서는 "/usr/pcapps"에 장착 된 파일 시스템에서 1,000,000 바이트 이상의 최대 200 파일을 찾고 있습니다.

"find"와 "xargs"사이의 Perl Line-Liner는 각 공백을 탈출/인용하므로 "Xargs"는 단일 인수로서 공백이 포함 된 모든 파일 이름을 "ls"로 전달합니다.

다른 답변에서 논의 된 대부분의 옵션은 GNU 유틸리티 (Solaris, AIX, HP-UX)를 사용하지 않는 플랫폼에서 표준이 아닙니다. 참조 posix '표준'Xargs 동작에 대한 사양.

또한 XARGS의 동작은 입력 없이도 적어도 한 번도 명령을 실행하여 성가신 것으로 나타났습니다.

나는 이름으로 공간의 문제를 다루기 위해 나만의 개인 버전의 Xargs (Xargl)를 썼습니다 ( 'find ... -print0'및 'xargs -0'조합은 파일 이름이 깔끔하지만 파일 이름은 깔끔합니다. ASCII NUL ' 0'문자를 포함합니다. 내 Xargl은 출판 할 가치가 있어야하는 것만 큼 완전하지 않습니다. 특히 GNU에는 적어도 좋은 시설이 있기 때문입니다.

BASH (POSIX 아님)를 사용하면 프로세스 대체를 사용하여 현재 라인을 변수 안에 넣을 수 있습니다. 이렇게하면 따옴표를 사용하여 특수 문자를 피할 수 있습니다.

while read line ; do cp "$line" ~/bar ; done < <(find . | grep foo)

나를 위해, 나는 조금 다른 일을하려고 노력했다. .txt 파일을 TMP 폴더에 복사하고 싶었습니다. .txt 파일 이름에는 공백과 아포스트로피 문자가 포함되어 있습니다. 이것은 내 Mac에서 작동했습니다.

$ find . -type f -name '*.txt' | sed 's/'"'"'/\'"'"'/g' | sed 's/.*/"&"/'  | xargs -I{} cp -v {} ./tmp/

시스템의 Find 및 XARG 버전이 지원하지 않으면 -print0 그리고 -0 스위치 (예 : AIX 찾기 및 XARG)이 끔찍한 코드를 사용할 수 있습니다.

 find . -name "*foo*" | sed -e "s/'/\\\'/g" -e 's/"/\\"/g' -e 's/ /\\ /g' | xargs cp /your/dest

여기서 SED는 Xargs의 공간과 인용문을 피할 것입니다.

AIX 5.3에서 테스트

나는 대부분의 문제를 해결하는 "xargs"주변에 "xargsl"이라는 작은 휴대용 래퍼 스크립트를 만들었습니다.

XARGS와 달리 Xargsl은 한 줄 당 하나의 PathName을 허용합니다. PathNames에는 (명백히) Newline 또는 Nul 바이트를 제외한 모든 문자가 포함될 수 있습니다.

파일 목록에 인용이 허용되거나 지원되지 않습니다. 파일 이름에는 모든 종류의 공백, 백 슬래시, 백 티크, 쉘 와일드 카드 문자 등이 포함될 수 있습니다.

추가 보너스 기능으로 Xargsl은 할 것입니다 ~ 아니다 입력이 없으면 한 번 명령을 실행하십시오!

차이점에 유의하십시오 :

$ true | xargs echo no data
no data

$ true | xargsL echo no data # No output

Xargsl에 주어진 모든 주장은 Xargs로 전달됩니다.

다음은 "xargsl"Posix Shell 스크립트입니다.

#! /bin/sh
# Line-based version of "xargs" (one pathname per line which may contain any
# amount of whitespace except for newlines) with the added bonus feature that
# it will not execute the command if the input file is empty.
#
# Version 2018.76.3
#
# Copyright (c) 2018 Guenther Brunthaler. All rights reserved.
#
# This script is free software.
# Distribution is permitted under the terms of the GPLv3.

set -e
trap 'test $? = 0 || echo "$0 failed!" >& 2' 0

if IFS= read -r first
then
        {
                printf '%s\n' "$first"
                cat
        } | sed 's/./\\&/g' | xargs ${1+"$@"}
fi

스크립트를 $ 경로에서 일부 디렉토리에 넣고 잊지 마십시오.

$ chmod +x xargsL

그것을 실행할 수 있도록 스크립트.

Bill_starr의 Perl 버전 내장 된 최신 라인 (공간이있는 대처)에는 잘 작동하지 않습니다. GNU 도구가없는 Solaris의 경우 더 완전한 버전이있을 수 있습니다 (SED 사용) ...

find -type f | sed 's/./\\&/g' | xargs grep string_to_find

필요에 따라 찾기 및 GREP 인수 또는 기타 명령을 조정하지만 SED는 임베디드 신형/공간/탭을 수정합니다.

나는 사용했다 빌 스타의 대답 Solaris에서 약간 수정 :

find . -mtime +2 | perl -pe 's{^}{\"};s{$}{\"}' > ~/output.file

이것은 각 줄 주위에 인용문을합니다. 아마도 도움이 될 것이지만 '-l'옵션을 사용하지 않았습니다.

내가 가고 있던 파일 목록에는 '-'가있을 수 있지만 신약은 아닙니다. XARGS를 통해 대량 삭제를 시작하기 전에 찾은 내용을 검토하고 싶기 때문에 다른 명령과 함께 출력 파일을 사용하지 않았습니다.

나는 이것을 조금 가지고 놀았고, Xargs 수정을 고려하기 시작했고, 우리가 여기서 이야기하고있는 종류의 사용 사례에 대해 Python의 간단한 재 구현이 더 나은 아이디어라는 것을 깨달았습니다.

우선, 모든 일에 대한 ~ 80 줄의 코드를 가지고있는 것은 무슨 일이 일어나고 있는지 알아 내기가 쉽고 다른 행동이 필요한 경우 얻는 데 걸리는 것보다 적은 시간에 새 스크립트에 해킹 할 수 있습니다. 스택 오버플로와 같은 어딘가에 답장.

보다 https://github.com/johnallsup/jda-misc-scripts/blob/master/yargs 그리고 https://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py.

yargs를 사용하여 작성 (및 Python 3 설치)을 입력하면 다음을 입력 할 수 있습니다.

find .|grep "FooBar"|yargs -l 203 cp --after ~/foo/bar

한 번에 203 개의 파일을 복사하려면. (여기서 203은 물론 자리 표시 자일 뿐이며 203과 같은 이상한 숫자를 사용하면이 숫자가 다른 의미가 없음을 분명히합니다.)

더 빠른 것을 원하고 파이썬이 필요하지 않으면 Zargs와 Yargs를 프로토 타입으로 가져 가서 C ++ 또는 C로 다시 작성하십시오.

다음과 같은 foobar 디렉토리를 grep해야 할 수도 있습니다.

find . -name "file.ext"| grep "FooBar" | xargs -i cp -p "{}" .

프레임 챌린지 - xargs 사용 방법을 묻고 있습니다.정답은:xargs는 필요하지 않기 때문에 사용하지 않습니다.

그만큼 댓글 작성자 user80168 모든 파일에 대해 cp를 호출하지 않고 cp를 사용하여 직접 이를 수행하는 방법을 설명합니다.

find . -name '*FooBar*' -exec cp -t /tmp -- {} +

이는 다음과 같은 이유로 작동합니다.

  • 그만큼 cp -t 플래그를 사용하면 시작 부분에 대상 디렉터리를 제공할 수 있습니다. cp, 끝이 가까워지기보다는.에서 man cp:
   -t, --target-directory=DIRECTORY
         copy all SOURCE arguments into DIRECTORY
  • 그만큼 -- 깃발이 말해준다 cp 이후의 모든 것을 플래그가 아닌 파일 이름으로 해석하므로 다음으로 시작하는 파일은 - 또는 -- 혼동하지 마십시오 cp;아직도 이것이 필요하기 때문에 -/-- 문자는 다음과 같이 해석됩니다. cp, 다른 특수 문자는 셸에서 해석됩니다.

  • 그만큼 find -exec command {} + 변형은 본질적으로 xargs와 동일합니다.에서 man find:

   -exec command {} +                                                     
         This  variant  of the -exec action runs the specified command on
         the selected files, but the command line is built  by  appending
         each  selected file name at the end; the total number of invoca‐
         matched  files.   The command line is built in much the same way
         that xargs builds its command lines.  Only one instance of  `{}'
         is  allowed  within the command, and (when find is being invoked
         from a shell) it should be quoted (for example, '{}') to protect
         it  from  interpretation  by shells.  The command is executed in
         the starting directory.  If any invocation  returns  a  non-zero
         value  as exit status, then find returns a non-zero exit status.
         If find encounters an error, this can sometimes cause an immedi‐
         ate  exit, so some pending commands may not be run at all.  This
         variant of -exec always returns true.

이것을 find에서 직접 사용하면 파이프나 쉘 호출이 필요하지 않으므로 파일 이름에 있는 불쾌한 문자에 대해 걱정할 필요가 없습니다.

Bash를 사용하는 경우 변환 할 수 있습니다 stdout 라인 배열로 mapfile:

find . | grep "FooBar" | (mapfile -t; cp "${MAPFILE[@]}" ~/foobar)

이점은 다음과 같습니다.

  • 내장되어 있으므로 더 빠릅니다.
  • 모든 파일 이름으로 명령을 한 번에 실행하므로 더 빠릅니다.
  • 다른 인수를 파일 이름에 추가 할 수 있습니다. 을 위한 cp, 당신은 또한 수:

    find . -name '*FooBar*' -exec cp -t ~/foobar -- {} +
    

    그러나 일부 명령에는 그러한 기능이 없습니다.

단점 :

  • 파일 이름이 너무 많으면 확장되지 않을 수 있습니다. (제한? 나는 모르겠지만, 데비안 아래 10000 개 이상의 파일 이름을 포함하는 10MB 목록 파일로 테스트했습니다)

글쎄 ... Bash가 OS X에서 사용할 수 있는지 누가 알겠습니까?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top