我有一个 zip 文件,其中包含名称很长的文件。
如果我尝试在命令行上提取文件,则会收到错误“文件名太长”。
如果我使用图形存档管理器,它不会提取文件,也不会让我重命名它们。如果我挂载存档,也会出现同样的问题。
我可以使用以下方法单独提取和重命名文件:
unzip -p -c example.zip "long file name.ogg" > shortname.ogg
对于大量文件来说这是不切实际的。
是否有一个工具可以在提取文件名时截断它们?
答案1
提取
我们可以将其用作zipinfo
这个过程的一部分,它是一个来自zip
包的程序。
zipinfo -2 example.zip
将只显示文件名称example.zip
,如下所示:
file1-long-name-...-bla-bla.html
file2-long-name-...-bla-bla.html
因此我们可以利用这个特性来提取所有文件:
zipinfo -2 example.zip | while read i;
do
long_fname=${i%.*}
unzip -p -c example.zip "$i" > "${long_fname:0:250}.${i##*.}"
done;
long_fname=${i%.*}
:从长文件名中删除扩展名,因此如果文件名少于 256 个字符,我们就不会得到重复的扩展名。${long_fname:0:250}.${i##*.}
:创建一个具有合法字符数的新文件名,并添加.
文件真实扩展名。
简单地说,我们循环进入文件列表,并使用 256 个字符的新合法文件名提取每个文件。
重命名
您可以使用zipnote
命令,它也是包的一部分zip
。
首先备份你的 zip 文件。
运行此命令:
zipnote example.zip > names
使用编辑器打开名称,它看起来像这样:
@ file name long in zip and a lot of other strings in the file name
@ (comment above this line)
@ (zip file comment below this line)
添加新的文件名,如下所示:
@ file name long in zip and a lot of other strings in the file name
@=new short name for above file
@ (comment above this line)
@ (zip file comment below this line)
然后重命名文件使用:
zipnote -w example.zip < names
您可以将它们全部重命名,也可以编写一个简单的脚本来自动为您执行此操作。
答案2
即使将输出文件名长度减少到 100,出于某种原因,另一个答案对我来说也不起作用,因此我只是一次性提取所有文件,unzip -p > all.txt
然后根据某种模式拆分all.txt
文件。csplit
请注意,解压缩将添加如下行
------=_Part_4952_1005066427.1638023175221
和
boundary="----=_Part_4953_1221949914.1638023175221"
它应该从输出中删除,并可能用于拆分文件,但我不需要这样做,因此如何正确地做到这一点留给练习:)
答案3
这是也可以处理长目录名的版本。您可以将其作为函数添加到 ~/.bashrc 或存储函数或别名的任何位置。
unziplong() {
max_base_len=100
max_ext_len=15
zipinfo -1 "$1" | grep -v "/$" | while read orig_path
do
new_path=""
current_path="$orig_path"
while [[ "$current_path" != "." ]]
do
segment="$(basename -- "$current_path")"
ext="$([[ "$segment" =~ .*\..{1,$max_ext_len}$ ]] && echo ".${segment##*.}" || echo)"
base="${segment%$ext}"
segment="/$(xargs <<< "${base:0:$max_base_len}")$(xargs <<< "$ext")"
new_path="$segment$new_path"
current_path="$(dirname -- "$current_path")"
done
new_path="${new_path:1}"
new_dir="$(dirname -- "$new_path")"
mkdir -p "$new_dir"
unzip -p "$1" "$orig_path" > "$new_path"
done
}