7z仅列出文件名

时间:2019-03-26 10:58:07

标签: cmd 7zip

我使用的是7z版本18.05,我只想列出存档内容的文件名。

如果我使用命令7z l myArchive.7z,则会得到以下输出:

7-Zip 18.05 (x64) : Copyright (c) 1999-2018 Igor Pavlov : 2018-04-30

Scanning the drive for archives:
1 file, 146863932 bytes (141 MiB)

Listing archive: myArchive.7z

--
Path = myArchive.7z
Type = 7z
Physical Size = 146863932
Headers Size = 393
Method = LZMA:26
Solid = +
Blocks = 1

Date       Time     Attr          Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2017-12-06 08:55:47 D...A            0            0  myArchive
2017-12-06 08:55:42 D...A            0            0  myArchive\folder
2017-12-05 19:50:41 ....A     21816530    146863539  myArchive\folder\Test.dat
2017-12-06 08:55:42 ....A     21877463               myArchive\folder\Test2.dat
2017-12-05 19:51:05 ....A       153953               myArchive\folder\Test3.dat
2017-12-05 19:50:41 ....A         4193               myArchive\folder\Test4.dat
2017-12-06 08:55:47 ....A     24128956               myArchive\log.txt
2017-12-06 08:55:47 ....A        79980               myArchive\readme.txt
2017-12-05 19:51:05 ....A   3256759999               myArchive\folder\zTest.txt
------------------- ----- ------------ ------------  ------------------------
2017-12-06 08:55:47         3324821074    146863539  7 files, 2 folders

我不知道为什么7z没有列出仅文件名的开关。如何仅获取“名称”列?有建议使用dos命令吗?

4 个答案:

答案 0 :(得分:2)

我正在寻找这个确切问题的答案,并在 Nisse Knudsen 提供的链接中找到了答案,但对我而言,-ba 未记录的开关本身无法完成我需要的功能,这个开关本身(也不是 Nisse 的答案)似乎也不能完全回答 OP 的问题 - OP 想知道如何只获取(每个文件的)名称,而 -ba 单独在解析数据时并不总是有效.7z 文件。我会发表评论而不是完整的答案,但我没有获得足够的代表来发表评论,我相信这些信息仍然相关且准确,无论如何我的“评论”都会太长。

使用 -slt 开关引用 Nisse (https://superuser.com/a/1073272/542975) 提供的链接以更易读的格式(用于循环/解析目的)格式化输出,其中一个简单的 For /f 循环一个批处理文件可以解析并为您提供所需的内容。

让我列出输出中的一些更改,以便您了解每个开关的作用。

这个:7z.exe l "C:\Some Directory\Some FileIZipped.zip"

7-Zip [64] 15.12 : Copyright (c) 1999-2015 Igor Pavlov : 2015-11-19

Scanning the drive for archives:
1 file, 9986888 bytes (10 MiB)

Listing archive: C:\Some Directory\Some FileIZipped.zip

--
Path = C:\Some Directory\Some FileIZipped.zip
Type = zip
Physical Size = 9986888

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2017-07-18 12:19:04 ....A       240789       109401  A_RandomFile.doc
2017-07-05 13:32:42 ....A     19148800      9877487  Another_Random File with Spaces.mov
------------------- ----- ------------ ------------  ------------------------
2017-07-18 16:30:44           19389589      9986888  2 files

变成这样:7z.exe l -slt "C:\Some Directory\Some FileIZipped.zip"

7-Zip [64] 15.12 : Copyright (c) 1999-2015 Igor Pavlov : 2015-11-19

Scanning the drive for archives:
1 file, 9986888 bytes (10 MiB)

Listing archive: C:\Some Directory\Some FileIZipped.zip

--
Path = C:\Some Directory\Some FileIZipped.zip
Type = zip
Physical Size = 9986888

----------
Path = A_RandomFile.doc
Folder = -
Size = 240789
Packed Size = 109401
    ----[10 lines of jargon removed for clarity]----

Path = Another_Random File with Spaces.mov
Folder = -
Size = 19148800
Packed Size = 9877487
    ----[10 lines of jargon removed for clarity]----

添加 -ba 命令进一步简化了格式,无需跳过标题行(我在 for 循环的注释中引用了这一点,如最后的脚本示例所示)。

这进一步变成:7z.exe l -ba -slt "C:\Some Directory\Some FileIZipped.zip"

Path = A_RandomFile.doc
Folder = -
Size = 240789
Packed Size = 109401
    ----[10 lines of jargon removed for clarity]----

Path = Another_Random File with Spaces.mov
Folder = -
Size = 19148800
Packed Size = 9877487
    ----[10 lines of jargon removed for clarity]----
  

我将此用作将存档 (zip/7z/rar) 与实际目录进行文件比较的方法,以制作该目录为主的镜像副本。为此,我正在解析一个包含 7z list 命令输出的文件。我想我可以直接从 7z 命令迭代 for 循环,但我发现在某些情况下,当档案中有大量数据时,这会变慢。

我有多个尝试解析标准输出失败的实例 - 当列出 .7z 存档的内容时会发生这种情况,如下所示。这不是 - 轻松 - 使用 for 循环解析空格来解决的。对于大多数行(显示为压缩空间)而言,Token 5 最终会成为 .zip 格式存档中保留的文件名 Token 6,因此您会遇到非常混乱的情况一场噩梦计划。这也是 OP 在提供的示例中引用的确切问题。

类似于 OP 提供的示例:

7-Zip [64] 15.12 : Copyright (c) 1999-2015 Igor Pavlov : 2015-11-19

Scanning the drive for archives:
1 file, 446600 bytes (437 KiB)

Listing archive: C:\Some Directory\Some _OTHER_ FileIZipped.7z

--
Path = C:\Some Directory\Some _OTHER_ FileIZipped.7z
Type = 7z
Physical Size = 446600
Headers Size = 283
Method = LZMA2:22
Solid = +
Blocks = 1

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2020-08-28 15:06:46 D....            0            0  SomeDirectoryInside
2020-08-28 15:06:46 D....            0            0  SomeDirectoryInside\OtherDir
2020-08-28 15:06:46 D....            0            0  SomeDirectoryInside\Zips
2020-08-28 15:13:14 .....      1064960       446317  SomeDirectoryInside\Zips\Some_File.Doc
2020-08-28 15:08:02 .....       313080               SomeDirectoryInside\Zips\Some_Other_File.Doc
2020-08-28 15:07:34 .....      1561728               SomeDirectoryInside\Zips\Foo.mov
2020-08-28 15:07:46 .....       262144               SomeDirectoryInside\Zips\Fancy.Doc
2020-08-28 15:07:26 .....       262144               SomeDirectoryInside\Zips\Fancy2.Doc
------------------- ----- ------------ ------------  ------------------------
2020-08-28 15:13:14            3464056       446317  5 files, 3 folders

下面是我编写的批处理脚本示例,用于将 7z.exe 输出放入文件中,然后从文件中提取数据并获取我需要的数据。原谅多个 REM 行 - 我更喜欢这种注释方法而不是长的单行字符串,这样读者就不必为了阅读而向右滚动代码块。

由于 For /f 如何遍历数据,我们需要确保令牌 %%c 不为空。我使用这种方法是因为有时我们的文件名称中有空格,我们使用空格作为分隔符来解析 7z 输出。

令牌 3* 会给你两个单独的令牌,你可以检查 - 令牌 %%b [ 令牌 3 ] 和 %%c [ 令牌 * ] - 如果 %%c 为空 -我们知道 %%b 没有空格,可以安全地回显到我们需要的任何文件或设置为稍后使用的变量等。

@Echo Off
  REM Sending the output of 7z into a file to use later
  7z.exe l -slt "SomeFileIZipped.zip" >"ZipListRAW.txt"
  
  REM Example of 7z.exe command with '-ba' switch
  REM 7z.exe l -ba -slt "SomeFileIZipped.zip"
  
  REM If you do not use '-ba' in the 7z command above, you can simply skip the first
  REM 11-12 lines of the file to get ONLY the filenames (skips past first line containing
  REM "Path" which contains the original archive filename.
  
  For /f "Usebackq Skip=11 Tokens=1,3* Delims= " %%a in ("ZipListRAW.txt") do (
    REM Checking if %%a equals word "Path"
    If "%%a"=="Path" (
      If [%%c]==[] (
        Echo %%b
      ) ELSE (
        Echo %%b %%c
      )
    )
  )

答案 1 :(得分:0)

如果可以在计算机上安装PowerShell模块,列出文件名就很容易了。这可以在任何受支持的现代Windows系统上完成。

https://www.powershellgallery.com/packages/7Zip4Powershell/1.9.0介绍了如何安装模块。

这是一个.bat文件脚本,显示其用法和输出。

C:>TYPE zipfnlist.bat
@ECHO OFF
SET "ZIP_FILENAME=.\7zIntf20.zip"
powershell -NoLogo -NoProfile -Command (Get-7Zip -ArchiveFileName "%ZIP_FILENAME%").FileName

C:>CALL zipfnlist.bat
bin
Properties
Ole32.cs
Program.cs
SevenZipFormat.cs
SevenZipInterface.cs
SevenZip.csproj
SevenZip.sln
bin\Debug
bin\Release
bin\Release\SevenZip.exe
Properties\AssemblyInfo.cs

答案 2 :(得分:0)

如果您不喜欢使用未记录的命令行开关的声音,您可以执行以下操作以从完整输出中解析出文件名。此 awk 脚本确定 Name 列标题的起始索引,并使用它从表中提取列。

awk_script='{
    if (ix == 0) {
        ix = index($0, "Name");
    }
    p = (body == 1);
    if (ix > 0) {
        # The table body is delimited by dashed lines, after the "Name" column header has been seen
        body = (body + ($0 ~ / *-[ -]+/)) % 2;
    }
    if (p == 1 && body == 1) {
        # Only print if "body" was 1 before and after the previous block; otherwise, we are in
        # the table body delimiter line (or outside the table completely)
        print substr($0, ix);
    }
}'

7z l your-file.7z | awk "$awk_script"

PowerShell 等效:

$ix=-1;
$body=$false;

& 7z l your-file.7z | foreach { `
    if ($ix -eq -1) {`
        $ix = $_.IndexOf("Name");`
    }`
    $p = $body;`
    if ($ix -gt 0) {`
        # The table body is delimited by dashed lines, after the "Name" column header has been seen`
        $body = ($body -ne ($_ -match ' *-[ -]+'))
    }`
    if ($p -and $body) {`
        # Only print if "body" was 1 before and after the previous block; otherwise, we are in`
        # the table body delimiter line (or outside the table completely)`
        write-output $_.Substring($ix)`
    }`
}

答案 3 :(得分:0)

我能够通过使用 -ba 标志为存档中的每个项目获取一行输出,然后使用 grep 解析每一行以仅获取文件名来实现此目的。

考虑这个例子,列出包含单个文件 baz 的档案的内容,该文件嵌套在两级目录 foobar 中。

user@host:~$  7z l -ba 'archive.7z'

结果如下:

2021-06-21 14:37:09 D....            0            0  foo
2021-06-21 14:37:41 D....            0            0  foo/bar
2021-06-21 14:37:41 ....A          881          524  foo/bar/baz

然后,使用 grep 只获取每行末尾的路径:

user@host:~$ 7z l -ba 'archive.7z' | grep -oP '\S+$'

给出输出:

foo
foo/bar
foo/bar/user1.lnk

如果您想列出包括目录在内的所有项目,那么您就完成了上述操作。就我而言,我实际上是想预览将使用 7z e 提取的项目,它只提取没有目录结构的文件,所以我补充说:

user@host:~$ 7z l -ba 'archive.7z' | grep -vF 'D....' | grep -oP '\S+$' | xargs basename

这给出了我想要的输出;对于这个例子:

user1.lnk