![我如何才能以递归方式压缩文件到它们自己的文件夹中?](https://linux22.com/image/1204039/%E6%88%91%E5%A6%82%E4%BD%95%E6%89%8D%E8%83%BD%E4%BB%A5%E9%80%92%E5%BD%92%E6%96%B9%E5%BC%8F%E5%8E%8B%E7%BC%A9%E6%96%87%E4%BB%B6%E5%88%B0%E5%AE%83%E4%BB%AC%E8%87%AA%E5%B7%B1%E7%9A%84%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%AD%EF%BC%9F.png)
我有以下目录结构:
/Data
- file 1
- file 2
/Folder1
- file 3
- file 4
/Folder2
- file 5
- file 6
/Folder3
- file 7
- file 8
在 Linux 中,我想要压缩每个目录中的文件(不包括文件夹),并在每个文件夹中创建一个 7z(或 zip)存档,结果如下:
/Data
Data.7z (Note: this should contain only file1 & 2, not any sub directories)
/Folder1
Folder1.7z (this should contain only file3 & 4, not any sub directories)
/Folder2
Folder2.7z (this should contain only file5 & 6, no Folder3)
/Folder3
Folder3.7z (should contain only file7 & 8)
以下脚本在第一个目录中有效,但在子目录中无效:
for i in */ ; do base=$(basename “$i”) ; cd $base ; 7za a -t7z -r $base * ; .. ; cd .. ; done;
我怎样才能实现这个目标?
答案1
如果你想使用7z
,棘手的部分似乎是说服它不是递归;文档中指出的-r-
开关似乎不起作用,建议的软件作者提供的解决方法是使用通配符表达式排除子目录-x!*/
因此,鉴于
$ tree Data
Data
├── file1
├── file2
├── Folder1
│ ├── file3
│ └── file4
├── Folder2
│ ├── file5
│ └── file6
└── Folder3
├── file7
└── file8
3 directories, 8 files
然后
find Data -type d -execdir sh -c 'cd "$1" && 7z a "$1".7z -x!*/ && cd -' sh {} \;
结果是
$ tree Data
Data
├── Data.7z
├── file1
├── file2
├── Folder1
│ ├── file3
│ ├── file4
│ └── Folder1.7z
├── Folder2
│ ├── file5
│ ├── file6
│ └── Folder2.7z
└── Folder3
├── file7
├── file8
└── Folder3.7z
3 directories, 12 files
例如,我们可以Folder2.7z
使用以下方法检查是否仅包含其自己的文件夹的文件
$ 7z l Data/Folder2/Folder2.7z
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_CA.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Core(TM)2 Duo CPU P9600 @ 2.53GHz (1067A),ASM)
Scanning the drive for archives:
1 file, 128 bytes (1 KiB)
Listing archive: Data/Folder2/Folder2.7z
--
Path = Data/Folder2/Folder2.7z
Type = 7z
Physical Size = 128
Headers Size = 128
Solid = -
Blocks = 0
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2018-02-12 18:37:37 ....A 0 0 file5
2018-02-12 18:37:37 ....A 0 0 file6
------------------- ----- ------------ ------------ ------------------------
2018-02-12 18:37:37 0 0 2 files
注意:在存在历史扩展运算符的!*/
环境中(例如交互式 bash shell),可能需要进行额外的转义。!
答案2
这是未经测试的代码,仅与“echo”一起使用,因为我不喜欢以多个 zip 文件结尾。这是幻想 zip 语法,因为我不知道 7za,但我会解释一下:
find . -type d -execdir /.../ad-hoc.sh {} ";"
脚本 ad-hoc.sh 必须使用绝对路径来寻址,并且不应位于当前路径中,以免影响结果,但它可能位于父目录中:
find . -type d -execdir $PWD/../ad-hoc.sh {} ";"
如果没有设为可执行,则明确调用:
find . -type d -execdir bash $PWD/../ad-hoc.sh {} ";"
Find 将在当前目录中查找,仅查找类型 d(目录)的文件,其中使用参数 {} 执行 bashscript,即找到的目录。
好的 - 我们在目录和子目录中执行的 ad-hoc.sh 是什么?这是另一个发现:
#!/bin/bash
dir=$1
find $dir -maxdepth 1 -type f -exec echo zip -o "$dir.zip" {} +
-maxdepth 1 防止 find 搜索子目录,-type 表示仅对文件进行操作。-exec 启动一个命令,用于测试“echo zip ...”,但如果它看起来很有希望(你经常做备份,不是吗?),你 - 好吧,这里开始我的伪代码:-o:= -output“$PWD.zip”,{} + 是文件列表。
tree
.
├── buch-klein.kry
├── buch.kry
├── crypt
│ ├── moveto.sh.crypt
│ └── sub1
│ ├── foo.crypt
│ └── sub2
│ └── bar.crypt
├── original
│ ├── 1
│ │ └── 2
│ │ └── 3
│ ├── moveto.sh
│ └── sub1
│ └── sub2
│ └── up3 -> ../../../nr
├── outputfile.txt
├── rot.sh
└── zoom.sh
find . -type d -execdir $PWD/../ad-hoc.sh {} ";"
zip -o ./..zip ././buch-klein.kry ././rot.sh ././buch.kry ././zoom.sh ././outputfile.txt
zip -o ./original.zip ./original/moveto.sh
zip -o ./crypt.zip ./crypt/moveto.sh.crypt
zip -o ./sub1.zip ./sub1/foo.crypt
zip -o ./sub2.zip ./sub2/bar.crypt
每个带有扩展名的文件都是常规文件,每个不带有扩展名的文件都是目录或指向目录的符号链接(up3)。
{} 必须是 find -exec 命令的最后一个元素,位于终止符“;”或 + 之前,因此您必须相应地构建 7z 命令。
所以如果你的 7za 命令是
7za a -t7z -r $dir.7za *
ad-hoc.sh 可能看起来像这样:
#!/bin/bash
dir=$1
find $dir -maxdepth 1 -type f -exec echo 7za -t7z -r "$dir.7za" {} +