파일을 찾아 tar (공백 포함)


110

좋아요, 여기에 아주 간단한 문제입니다. 저는 간단한 백업 코드를 작성 중입니다. 파일에 공백이있는 경우를 제외하고는 잘 작동합니다. 이것이 내가 파일을 찾고 tar 아카이브에 추가하는 방법입니다.

find . -type f | xargs tar -czvf backup.tar.gz 

문제는 tar가 폴더라고 생각하기 때문에 파일 이름에 공백이있는 경우입니다. 기본적으로 find 결과에 따옴표를 추가 할 수있는 방법이 있습니까? 아니면 이것을 고치는 다른 방법?


12
사용하는 가장 좋은 방법 find ... | xargs ...은 각각에 -print0 / -0 매개 변수를 사용하는 것 find -print0 ... | xargs -0 ...입니다. 이렇게하면 파일 이름이 널 문자로 구분됩니다. 즉, 파일 이름에 공백이나 줄 바꿈 또는 기타 이상한 내용이있을 수 있으며 여전히 작동합니다.
porges

8
많은 수의 파일이있을 때 xargs와 tar를 사용하는 데 문제가 있습니다. xargs는 tar -c를 반복적으로 호출하므로 아카이브를 계속 덮어 쓰게되며 결과적으로 예상 한 모든 파일을 사용할 수 없습니다. . 참조 이 자세한 설명내 대답은 아래를.
Steve Kehlet 2012 년

답변:


217

이것을 사용하십시오 :

find . -type f -print0 | tar -czvf backup.tar.gz --null -T -

그것은 :

  • 공백, 개행, 선행 대시 및 기타 재미있는 파일 처리
  • 무제한의 파일 처리
  • 많은 파일이있을 때 tar -cwith xargs를 사용 하는 것처럼 backup.tar.gz를 반복적으로 덮어 쓰지 않습니다.

참조 :


1
먼저 몇 번 sed를 통해 찾은 결과를 파이프하려면 어떻게해야합니까? 예를 들어. -print0 | sed / backups / d | tar ....
Brad Parks

8
조건이 여러 개인 경우 괄호를 추가해야합니다. 그렇지 않으면 -print0마지막 표현식에만 적용됩니다. 예find . \( -type f -o -name '*.c' \) -print0 | ...
nimrodm

1
재미를 위해 여기 cygwin을 사용하는 Windows 버전이 있습니다.c:\cygwin\bin\find . -regextype posix-egrep -regex '.*(sln^|vcxproj^|filters)$' -print0 | c:\cygwin\bin\tar -cvf MS_Projects.tar --null -T -
Jon

1
@Steve는 tar 명령 끝에 '-'옵션이 무엇인지 설명해 주시겠습니까? GNU tar의 man 페이지에서 찾을 수 없습니다.
shaffooo

물론,에 대한 매개 변수 -T이며 표준 입력에서 파일 이름을 읽는 것을 의미합니다.`--files-from '의 파일 이름으로 단일 대시를 제공하면 (즉, --files-from =을 지정합니다. -또는 -T-), 파일 이름은 표준 입력에서 읽습니다.
Steve Kehlet 2017 년

14

원하는 것을 달성하는 다른 방법이있을 수 있습니다. 원래,

  1. find 명령을 사용하여 원하는 파일의 경로를 출력 하십시오 . stdout 을 선택한 파일 이름으로 리디렉션 합니다.
  2. 그런 다음 -T 옵션과 함께 tar를 사용하여 파일 위치 목록을 가져올 수 있습니다 (방금 find!로 만든 위치).

    find . -name "*.whatever" > yourListOfFiles
    tar -cvf yourfile.tar -T yourListOfFiles
    

대답은 그들에 줄 바꿈와 파일 이름을 처리하는 방법 여기에 있습니다 : superuser.com/a/513319/151261
tommy.carstensen

8

다음을 실행 해보십시오.

    find . -type f | xargs -d "\n" tar -czvf backup.tar.gz 

7

왜 안 되는가 :

tar czvf backup.tar.gz *

물론 find를 사용하고 xargs를 사용하는 것이 영리하지만 어려운 방식으로 수행하고 있습니다.

업데이트 : Porges는 내 답변 또는 다른 답변보다 더 나은 답변이라고 생각하는 찾기 옵션으로 댓글을 달았습니다. find -print0 ... | xargs -0 ....


내 전체 코드는 지난 하루에 수정 된 항목 만 백업합니다. 매일 백업하기 때문에 파일 크기를 저장하기 위해 반복되는 정보를 원하지 않습니다 (15 일마다 전체 백업을합니다).
Caleb Kester

더 나은 SO 질문을 만들기 위해 "안정적으로 find, xargs, tar를 함께 사용하는 것"에 대한 질문을하겠습니다. 귀하의 제목과 질문은 find 및 xargs가 필요하다는 것을 실제로 지정하지 않지만 아직 수행합니다.
Warren P

xargs ... tar c ...파일 목록이 너무 길면 생성 된 첫 번째 아카이브를 덮어 쓰고 두 번째로 xargs실행 tar됩니다! 덮어 쓰기를 방지하기 위해 사용할 수 xargs -x있지만 아카이브가 불완전 할 수 있습니다. 대안은 처음 tar c ...에 다음 가능하면 반복 할 수 있습니다 tar r .... (신뢰성에 대한 나의 공헌 :)
pabouk

3

여러 파일 또는 디렉토리가 있고이를 독립적 인 *.gz파일 로 압축하려는 경우이 작업을 수행 할 수 있습니다. 선택 과목-type f -atime

find -name "httpd-log*.txt" -type f -mtime +1 -exec tar -vzcf {}.gz {} \;

이것은 압축됩니다

httpd-log01.txt
httpd-log02.txt

httpd-log01.txt.gz
httpd-log02.txt.gz

2

다음과 같은 것을 시도해보십시오. tar cvf scala.tar `find src -name *.scala`



2

@Steve Kehlet 게시물에 댓글을 추가 할 수 있지만 50 명의 담당자 (RIP)가 필요합니다.

수많은 인터넷 검색을 통해이 게시물을 찾은 사람을 위해 특정 시간 범위에서 특정 파일을 찾을뿐만 아니라 tarring 오류를 유발할 수있는 상대 경로 나 공백을 포함하지 않는 방법을 찾았습니다. (정말 감사합니다.)

find . -name "*.pdf" -type f -mtime 0 -printf "%f\0" | tar -czvf /dir/zip.tar.gz --null -T -
  1. . 상대 디렉토리

  2. -name "*.pdf" PDF (또는 모든 파일 형식)를 찾습니다.

  3. -type f 찾을 유형은 파일입니다.

  4. -mtime 0 지난 24 시간 동안 생성 된 파일 찾기

  5. -printf "%f\0"정규 -print0OR -printf "%f"는 나를 위해 작동하지 않았습니다. man 페이지에서 :

이 인용은 GNU ls와 같은 방식으로 수행됩니다. 이것은 -ls 및 -fls에 사용되는 것과 동일한 인용 메커니즘이 아닙니다. find 출력에 사용할 형식을 결정할 수 있다면 일반적으로 파일 이름에 공백과 개행 문자가 포함될 수 있으므로 개행 문자를 사용하는 것보다 종결 자로 '\ 0'을 사용하는 것이 좋습니다.

  1. -czvf 아카이브 생성, gzip을 통해 아카이브 필터링, 처리 된 파일을 상세하게 나열, 아카이브 이름

편집 2019-08-14 : 추가하고 싶습니다. 타르 자체를 사용하여 기본적으로 동일한 명령을 내 의견에 사용할 수도 있습니다.

tar -czvf /archiveDir/test.tar.gz --newer-mtime=0 --ignore-failed-read *.pdf

--ignore-failed-read오늘날 새로운 PDF가없는 경우에 필요 합니다.


1

가장 좋은 해결책은 다른 소스를 사용하고 목록으로 다른 작업을 수행 할 수 있기 때문에 파일 목록을 만든 다음 파일을 보관하는 것 같습니다.

예를 들어이 목록을 사용하여 아카이브되는 파일의 크기를 계산할 수 있습니다.

#!/bin/sh

backupFileName="backup-big-$(date +"%Y%m%d-%H%M")"
backupRoot="/var/www"
backupOutPath=""

archivePath=$backupOutPath$backupFileName.tar.gz
listOfFilesPath=$backupOutPath$backupFileName.filelist

#
# Make a list of files/directories to archive
#
echo "" > $listOfFilesPath
echo "${backupRoot}/uploads" >> $listOfFilesPath
echo "${backupRoot}/extra/user/data" >> $listOfFilesPath
find "${backupRoot}/drupal_root/sites/" -name "files" -type d >> $listOfFilesPath

#
# Size calculation
#
sizeForProgress=`
cat $listOfFilesPath | while read nextFile;do
    if [ ! -z "$nextFile" ]; then
        du -sb "$nextFile"
    fi
done | awk '{size+=$1} END {print size}'
`

#
# Archive with progress
#
## simple with dump of all files currently archived
#tar -czvf $archivePath -T $listOfFilesPath
## progress bar
sizeForShow=$(($sizeForProgress/1024/1024))
echo -e "\nRunning backup [source files are $sizeForShow MiB]\n"
tar -cPp -T $listOfFilesPath | pv -s $sizeForProgress | gzip > $archivePath

이것에 대한 하나의 라이너?
Robino
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.