Như Mathias đã nói, unzip
không có tùy chọn như vậy, nhưng một tập lệnh bash một lớp có thể thực hiện công việc.
Vấn đề là: cách tiếp cận tốt nhất phụ thuộc vào bố cục lưu trữ của bạn. Một giải pháp giả định một thư mục cấp cao nhất sẽ thất bại thảm hại nếu nội dung trực tiếp trong thư mục gốc lưu trữ (suy nghĩ /a/foo
/b/foo
/foo
và sự hỗn loạn của tước /a
và /b
).
Và thất bại tương tự xảy ra với tar --strip-component
. Không có giải pháp một kích cỡ phù hợp cho tất cả.
Vì vậy, để tước dir gốc, giả sử có là một (và chỉ một):
unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"
Chỉ cần đảm bảo các tệp / thư mục cấp hai không có cùng tên của cha mẹ cấp cao nhất (ví dụ /foo/foo
:). Nhưng /foo/bar/foo
và /foo/bar/bar
đều ổn. Nếu họ làm như vậy, hoặc bạn chỉ muốn an toàn, bạn có thể sử dụng thư mục tạm thời để trích xuất:
temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
mv "$temp"/*/* "$dest" && rmdir "$temp"/* "$temp"
Nếu bạn đang sử dụng Bash, bạn có thể kiểm tra xem cấp cao nhất có phải là một thư mục đơn hay không sử dụng:
f=("$temp"/*); (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] && echo "Single dir!"
Nói về Bash, bạn nên bật dotglob
để bao gồm các tệp ẩn và bạn có thể gói mọi thứ trong một chức năng duy nhất, tiện dụng:
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"
)
Bây giờ hãy đặt nó trong ~/.bashrc
hoặc hoặc ~/.profile
bạn sẽ không bao giờ phải lo lắng về điều đó nữa. Đơn giản chỉ cần sử dụng như:
unzip-strip sourcefile.zip mysubfolder
(chú ý nó sẽ tự động tạo mysubfolder
cho bạn nếu nó không tồn tại)