'tar'명령과 'find'를 결합하는 방법


31

find 명령은 다음과 같은 출력을 제공합니다.

[root @ localhost /] # var / log / -iname anaconda를 찾으십시오. *
var / log / anaconda.log
var / log / anaconda.xlog
var / log / anaconda.yum.log
var / log / anaconda.syslog
var / log / anaconda.program.log
var / log / anaconda.storage.log

tar와 결합하면 다음 출력이 표시됩니다.

[root @ localhost /] # find var / log / -iname anaconda. * -exec tar -cvf file.tar {} \;
var / log / anaconda.log
var / log / anaconda.xlog
var / log / anaconda.yum.log
var / log / anaconda.syslog
var / log / anaconda.program.log
var / log / anaconda.storage.log

그러나 tar 파일을 나열하는 동안 단일 파일 만 표시됩니다.

[root @ localhost /] # tar -tvf 파일 .tar
-rw ------- 루트 / 루트 208454 2012-02-27 12:01 var / log / anaconda.storage.log

내가 여기서 뭘 잘못하고 있니?

xargs를 사용하면이 출력을 얻습니다.

[root @ localhost /] # find var / log / -iname 아나콘다. * | xargs tar -cvf 파일

두 번째 질문

var 앞에 / 를 입력하는 동안 find /var/log왜 mesaage tar를 제공 하는지를 의미합니다 . 멤버 이름에서 선행`/ '제거

[root @ localhost /] # find / var / log / -iname anaconda. * -exec tar -cvf file.tar {} \;
tar : 멤버 이름에서 선행`/ '제거
/var/log/anaconda.log
tar : 멤버 이름에서 선행`/ '제거
/var/log/anaconda.xlog
tar : 멤버 이름에서 선행`/ '제거
/var/log/anaconda.yum.log
tar : 멤버 이름에서 선행`/ '제거
/var/log/anaconda.syslog
tar : 멤버 이름에서 선행`/ '제거
/var/log/anaconda.program.log
tar : 멤버 이름에서 선행`/ '제거
/var/log/anaconda.storage.log

간단한 형태로 다음 두 가지의 차이점은 무엇입니까?

find var/logfind /var/log


이 주제는 세미 + 오프 주제이지만 find명령을 계속 진행 하면서 검색어를 인용해야합니다. 때로는 그렇지는 않지만 항상 작동하지는 않습니다.
nerdwaller 2016

1
{} +대신 사용하면 {} \;find 결과를 하나의 인수로 그룹화합니다.
Jason S

답변:


39

참고 : 다소 효율적인 솔루션은 @Iain의 답변 을 참조하십시오 .

참고 find부르는 것 -exec에 대한 행동 마다 하나의 파일 이 발견합니다.

tar -cvf file.tar {}모든 단일 파일 find출력에 대해 실행하는 경우 매번 덮어 쓰게 되므로 마지막 파일 출력 인 file.tar하나의 아카이브 만 남게되는 이유를 설명합니다 .anaconda.storage.logfind

이제 실제로 매번 파일을 생성하는 대신 파일을 아카이브 에 추가 하려고합니다 ( -c옵션이 수행하는 작업). 따라서 다음을 사용하십시오.

find var/log/ -iname "anaconda.*" -exec tar -rvf file.tar {} \;

-r옵션은 매번 다시 작성하는 대신 아카이브에 추가합니다.

참고 : 교체 -iname anaconda.*와 함께 -iname "anaconda.*". 별표는 와일드 카드이므로 셸을 통해 확장 할 수도 있습니다 find. 이 확장을 막으려면 인수를 큰 따옴표로 묶으십시오.


tar선행 을 제거하는 경우 /: 아카이브는 상대 파일 이름 만 포함해야 합니다. Leading 파일을 추가하면 절대 파일 이름 /으로 저장됩니다 ( 예 : 컴퓨터에 그대로 의미) ./var/…

IIRC 이것은 tarGNU 이외의 구현에 대한 예방책 일 뿐이며 /var/…상대 파일 이름이 포함 된 아카이브를 추출 할 때 실제 데이터를 덮어 쓰지 않기 때문에이 방법이 더 안전합니다 .


6
그러나이 tar방법으로 실제 테이프 아카이브를 사용하여 한 번에 하나의 파일을 추가하고 테이프를 되 감은 다음 매번 모든 것을 다시 읽으면 끝까지 도달하면 모든 것이 엄청나게 느려집니다. tar 파일을 디스크에 쓰는 경우 에만 솔루션이 적합합니다.
Nicole Hamilton

2
사실, 그러나 나는 우리가 안전하게이 문제를 무시할 수 있다고 생각)
slhck

@slhck *는 모든 가능성과 일치하는 와일드 카드입니까? 그러나 여기에 find /var/log/ -iname anaconda*아무것도주지 않고 결과를 find /var/log/ -iname anaconda.*주는 이유는 무엇입니까?
최대

와일드 카드를 사용하면 find더 이상 와일드 카드를 볼 수 없습니다. 따라서 anaconda*현재 폴더에 anaconda5(이 와일드 카드와 일치하는)와 같은 이름이있는 경우 와일드 카드가 확장되어 대신에 find표시 -iname anaconda5됩니다 -iname anaconda*. 첫 번째가 작동하지 않고 두 번째가 작동하는 이유는 현재 디렉토리에있는 파일에 따라 다릅니다. @max
slhck

2
{} +대신 {} \;찾기를 사용하여 찾기 결과를 하나의 인수로 그룹화 할 수 있습니다.
Jason S

41

다음과 같은 것을 사용할 수 있습니다.

find var/log -iname 'anaconda.*' -print0 | tar -cvf somefile.tar --null -T -

-print0-T함께 작업은 최종 등 스페이스 바꿈과 파일명을 허용하는 -표준 입력으로부터 입력 된 파일 이름을 읽어 타르 말한다.

-print0당, 명세서의 끝에 와야 이 답변 . 그렇지 않으면 예상보다 많은 파일을 얻을 수 있습니다.


2
-name옵션을 생략 하여 솔루션을 tar전체 디렉토리로 만듭니다. 그것이 당신이 원하는 것이라면, 당신은 tar -cvf file.tar var/log전혀 사용하지 않고 더 쉽게 할 수 있습니다 find.
Nicole Hamilton

2
+1 목록을 파이핑 tar하는 것이 좋습니다. 경로 이름에 공백이있을 것으로 예상되는 경우 확실히 최고의 솔루션입니다. 신뢰할 수 있고 효율적이기 때문에 기술적으로 최고라고 설명합니다. 그러나 find와에 대한 추가 특수 지식이 필요합니다 tar. 명령 대체는 더 일반적인 도구이기 때문에 명령 대체를 선호합니다. 한 번만 사용하고 어디서나 사용하는 방법을 배우십시오. (그러나 나는 항상 그것이 작동하는 쉘이있는 Windows에 있음을 인정합니다.) 무례한 것처럼 보인다면 사과드립니다.
Nicole Hamilton

2
이미 +1을 받았습니다. 행복하세요 :) 긴 명령 행은 항상 모든 OS에서 프로세스 작성 i / f의 단점입니다. 나는 90 년대 초에 Microsoft의 Mark Lucovsky 와 NT의 32K 유니 코드 문자 제한이 너무 작아서 커널의 어느 곳에서나 짧은 길이가 아닌 긴 길이를 저장하는 데 얼마나 많은 바이트가 필요한지 알지 못했다고 주장한 것을 기억 합니다. . 한숨. arg 목록이 너무 길 때 더 일반적인 경우 해결책은 쉘에서 더 많은 작업을 수행하거나 (가능한 경우 내에서) 사용하는 것 xargs입니다.
Nicole Hamilton

9
find -print0옵션 을 사용하는 경우 tar --null옵션 도 필요합니다 .
mivk

2
그리고 --no-unquote파일 이름이 포함 된 백 슬래시 그렇지 않으면 잘못된 취급 될 것이다 : 잘은 다음과 같이 필요 끈다. (아니, 이것은 가설이 아닙니다. 저는 이름에 백 슬래시가있는 파일 이름을 포함하는 다른 사람의 코드로 tar 아카이브를 만들고 있습니다.
hvd

12

이 시도:

tar -cvf file.tar `find var/log/ -iname "anaconda.*"`

에 사용하려고 find했습니다 -exec tar. 그러나 -exec옵션이 작동 하는 방식에서는 찾은 일치하는 파일마다 해당 명령을 한 번 실행하여 매번 tar생성되는 tar 파일을 덮어 씁니다. 그렇기 때문에 당신은 마지막으로 끝났습니다. 또한 지정한 패턴 주위에 따옴표를 넣어서 find셸이을 전달하기 전에 확장하지 않도록해야합니다 find.

백틱으로 명령 대체를 사용하거나 $(...)원하는 경우 표기법을 사용하여 생성 된 전체 이름 목록이 find에 대한 인수로 명령 행에 다시 붙여져 tar한 번에 모두 작성됩니다.


2
find는 이름, 줄 바꿈 또는 globbing 문자에 공백이있는 출력 파일을 찾으면 좋지 않을 수 있습니다. 이것은 실패 할 수밖에 없습니다. stdout을 배관 find하는 것은 좋은 생각이 아닙니다. mywiki.wooledge.org/ParsingLs
slhck

3
@slhck, find에서 파이프 stdout을 파이핑하는 것은 실제로 의견에 링크 된 페이지에서 매우 명확하게 설명 된 것처럼 일반적으로 좋습니다. 실제로 권장되는 방법입니다. 당신은 (같은 몇 가지 트릭을 사용한다 read -r의를 -print0내가 내 대답에 그랬던 것처럼).
terdon

4
@slhck Unix 및 Linux의 파일 및 디렉토리 이름이 전통적으로 이름의 공백을 피한 이유입니다. 또한 공백이있는 Windows의 경우 전체 줄 (공백 포함)을 단일 단어로 처리하여 명령에 다시 붙여 넣을 수있는 이중 백 틱을 사용하여 해밀턴 C 쉘에 명령 대체 표기법을 추가했습니다. 선. 불행히도, 유닉스 쉘에는 그 기능이 없습니다.
Nicole Hamilton

1
그들은 전통적으로 그것을 피했을 수도 있지만 GUI를 통해 사용자 공간에서 파일을 만들면 더 이상 공백이있는 파일을 무시하고 2 차 시민으로 취급 할 수 없습니다 (유닉스이기 때문에). 쉘에 포함시키는 것이 좋지만 Windows 용이며 Unix 쉘은 올바른 구문을 사용하고 적절한 예방 조치를 취하면 특히 해당 기능이 필요 하지 않습니다 . 그래서 처음에 내 의견을 게시했습니다.
slhck December

2
아니요, 그러나 다른 곳에서는 아주 잘 일어날 수 있습니다. 그렇기 때문에 방어 적으로 프로그래밍하는 것이 좋습니다. 미안보다 안전합니다. 또한이 질문을 찾는 방문자는 반드시 똑같은 문제가 아니며 여기에서 찾은 명령 이이 경우에 효과가 있지만 왜 실패했는지 궁금합니다. 명령을 고치기 위해 당신에게 맡기겠습니다. 많은 사람들이 조만간이 문제에 부딪 치기 때문에 명령을 언급하는 것이 중요하다고 생각했습니다.
slhck December

6

질문 1

tar찾은 각 파일을 가져 와서에 보관 하기 때문에 명령이 실패합니다 file.tar. 그렇게 할 때마다 이전에 작성된을 덮어 씁니다 file.tar.

원하는 파일이 모두있는 하나의 아카이브 tar인 경우 직접 실행하면 필요하지 않습니다 find(그리고 이름에 공백이있는 파일에 대해서는 가능합니다).

tar -vcf file.tar /var/log/anaconda*   

질문 2

두 명령은 완전히 다릅니다.

  • 라는 디렉토리를 검색합니다 VAR / 로그 찾을 var/log 현재 디렉토리의 하위 디렉토리 , 그것은 동일합니다 find ./var/log(통지 ./).

  • find / var / log는 /var/log 루트의 하위 디렉토리 인/ 디렉토리를 검색합니다 .

주요 /메시지는 님이 tar아닙니다 find. /파일 이름 의 첫 번째 파일을 제거하여 상대 경로로 절대 경로 를 만듭니다 . 즉, 보관 파일을 압축 해제 할 때 의 파일 이 추출됩니다 ./var/log/anaconda.error./var/log/anaconda.error


1

-exec작동 할 수 있는 두 가지 방법 이 있습니다. 한 가지 방법은 각 파일마다 한 번씩 명령을 여러 번 실행합니다. 다른 방법은 모든 파일을 매개 변수 목록으로 포함하여 명령을 한 번 실행합니다.

  • -exec tar -cvf file.tar {} ';'tar각 파일에 대해 명령을 실행하여 매번 아카이브를 덮어 씁니다.
  • -exec tar -cvf file.tar {} '+'tar명령을 한 번 실행하여 발견 된 모든 파일의 아카이브를 작성합니다.

1

파일이 많은 경우 각 파일에 -exec를 사용하면 tar 압축이 매우 느려질 수 있습니다. 나는 명령을 선호한다 :

find . -iname "*.jpg" | cpio -ov -H tar -F jpgs.tar

실패 할 때까지/bin/cpio: xxx: Cannot open: Too many open files
SYN
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.