압축 해제 된 tar의“--strip-components = 1”과 동일합니까?


48

tar.gz 파일을 지정된 하위 디렉토리 mysubfolder 로 추출하는 스크립트가 있습니다 .

mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;

zip 파일 로이 작업을 수행하는 동등한 방법이 있습니까?


2
그냥 bsdtar를 사용하십시오
drizzt

답변:


26

Mathias가 말했듯 unzip이 그러한 옵션은 없지만 한 줄짜리 bash 스크립트가 작업을 수행 할 수 있습니다.

문제는 : 가장 좋은 방법은 아카이브 레이아웃에 따라 다릅니다. 컨텐츠가 아카이브 루트에 직접있는 경우 단일 최상위 디렉토리 를 가정 하는 솔루션은 비참하게 실패합니다 ( /a/foo /b/foo /foo탈피 /a와 의 혼돈에 대해 생각 하십시오 /b).

그리고 같은 실패가 발생합니다 tar --strip-component. 모든 규모에 맞는 솔루션은 없습니다.

그래서,이 가정의 루트 디렉토리를 제거 할 수 있습니다 하나의 (그리고 오직 하나) :

unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"

그냥 확실히 두 번째 수준 파일 / DIRS 할 수 있도록 하지 (예를 들어, 최상위 부모의 같은 이름을 가진 /foo/foo). 그러나 /foo/bar/foo/foo/bar/bar확인합니다. 그들이하거나 안전하고 싶다면 추출을 위해 임시 디렉토리를 사용할 수 있습니다.

temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
mv "$temp"/*/* "$dest" && rmdir "$temp"/* "$temp"

Bash를 사용하는 경우 최상위 레벨이 단일 디렉토리인지 또는 다음을 사용하지 않는지 테스트 할 수 있습니다.

f=("$temp"/*); (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] && echo "Single dir!"

Bash에 관해서 dotglob는 숨겨진 파일을 포함하도록 켜야하며 모든 것을 하나의 편리한 기능으로 래핑 할 수 있습니다.

unzip-strip() (
    local zip=$1
    local dest=${2:-.}
    local temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
    shopt -s dotglob && local f=("$temp"/*) &&
    if (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] ; then
        mv "$temp"/*/* "$dest"
    else
        mv "$temp"/* "$dest"
    fi && rmdir "$temp"/* "$temp"
)

지금 당신의 ~/.bashrc또는 ~/.profile그것을 넣어 당신은 그것에 대해 다시 걱정할 필요가 없습니다. 간단히 다음과 같이 사용하십시오.

unzip-strip sourcefile.zip mysubfolder

( mysubfolder없는 경우 자동으로 생성됩니다 )


원하는대로 기존 디렉토리 구조로 압축을 풀지 않습니다 (mysubfolder 대신.을 사용하려고했습니다). 압축을 풀고 (zip-zip-with-top-dir.zip 압축) 복사 한 다음 (cp -rv extract-top-zip-dir / *) 복사했습니다.
catgofire

4

대한 매뉴얼 페이지unzip 에서 이러한 옵션을 찾을 수 없으므로 이것이 불가능한 것 같습니다. :(

그러나 (상황에 따라) 해결할 수 있습니다. 예를 들어, zip 파일의 유일한 최상위 디렉토리 이름 foo-과 버전 번호 가 확실하다면 다음과 같이 할 수 있습니다.

cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder

좋은 접근 방법이지만 약간 불완전합니다. 완전히 추출 된 내용이있는 foo * dir이 있습니다.
MestreLion

예, rm -rf foo-*잠재적으로 위험하므로 의도적으로 추가하지 않았습니다 . 이미 이름이 지정된 폴더가 있다면 어떻게 foo-bar합니까? 추출은 /tmp폴더 내에서 수행되며 , 매번 자동으로 비워집니다.
Mathias Bynens

그렇기 때문에 &&주어진 단계는 이전 단계가 성공한 경우에만 발생하므로 마지막 단계 ( rm)는 모든 단계가 오류없이 완료된 경우에만 실행됩니다 .
MestreLion

2
그렇기 때문에 /tmp/some-hardcoded-folder-name임시 폴더로 사용자 를 사용해서는 안되며 대신 mktemp기존 폴더를 사용하지 않아야합니다. 아래에서 내 대답을 확인하십시오.
MestreLion

1

-j경로를 정크로 만드는 데 사용할 수 있습니다 (디렉토리를 만들지 마십시오). 이것은 다소 일반적인 단일 레벨 아카이브에만 권장됩니다. 여러 수준의 디렉토리 구조를 가진 아카이브는 평평해질 것입니다. 이로 인해 파일을 추출 할 때 이름이 충돌 할 수도 있습니다.

압축 해제 매뉴얼 페이지에서 :

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.