在Linux中如何每行输出一个文件名?

337
我正在使用ls -a命令获取目录中的文件名,但输出结果是单行显示的。
像这样:
.  ..  .bash_history  .ssh  updater_error_log.txt

我需要一种内置的替代方法来获取文件名,每个文件名都在新行中,就像这样:

.  
..  
.bash_history  
.ssh  
updater_error_log.txt

3
ls命令旨在显示一个人类可读的列表。如果你将ls用于其他任何目的(比如说,在脚本中获取文件列表进行迭代),那么你肯定使用了错误的工具。 - Juliano
4
@juliano - 实际上它是由Python脚本消耗的。你为什么说它是错误的工具? - fixxxer
2
@fixxer 当你将ls管道传递到Python时,ls会按照我在答案中解释的方式每行输出一个文件。 - Peter G.
7
如果你使用ls命令的原因是为了获取未经格式化的文件名,那么你其实是在错误地使用该命令。ls命令是将列表格式化以便在用户终端输出。它可能会替换文件名中的特殊字符,省略具有特殊含义的字符等等。换句话说,ls命令是格式化用户列表的。你想要的是未经格式化的文件名。你不使用Python的'glob'模块有什么特殊的原因吗?http://docs.python.org/library/glob.html 还有'fnmatch'、'dircache'和其他模块也可以试试。 - Juliano
1
@fixxer 你是否确实让“ls”输出到“Python”,并观察了Python中的单行输出? - Peter G.
显示剩余2条评论
8个回答

627

使用-1选项(注意这是数字“1”,而不是小写字母“L”),像这样:

ls -1a
首先,请确保您的ls支持-1。GNU coreutils(安装在标准Linux系统上)和Solaris都支持;但如果不确定,请使用man lsls --help或查看文档。例如:
$ man ls
...
       -1     list one file per line.  Avoid '\n' with -q or -b

5
+1 我不知道关于-1(-l是小写字母L,而不是数字1)。它在手册中有提到,但我一直把它读成字母 L。 :) - slashmais
1
@dty:对于GNU,你可以在ls --help的输出中找到这个记录...总是已安装的;-) - Tony Delroy
3
在谷歌上搜索“linux ls 每行一个文件”,这是最受欢迎的文章。无法相信被选中的答案有多么冗长,或者这个答案的投票比使用管道到cat的那个答案少。ls -1胜利了。 - crantok
8
当输出未连接到终端时,ls 默认使用 -1 行为。 - codeforester
非常有用且快速,可以复制文件列表到电子表格或其他地方,而无需使用pandas! - sugab
显示剩余2条评论

160

是的,您可以轻松地使ls输出每行一个文件名:

ls -a | cat

解释:命令ls会感知输出是否是在终端还是文件或管道,并进行相应的调整。

因此,如果你将ls -a导出到python中,不需要任何特殊措施即可运行。


3
哇,这太棒了。与已接受的答案相比,这个解决方案实际上适用于Android / adb shell,而ls仅是某些简化版本,因此不支持“-1”。 - mkilmanas
1
如何避免在输出中显示“.”和“..”这些“文件”? - matanster
1
这取决于你是否想要查看所有的点文件(dot-files)。如果不需要,就省略-a选项即可。 - Peter G.
1
@matanster,“ls -A”不是获取除“.”和“..”之外的所有文件的方法吗? - Orlando Rivera Letelier

34

Ls 的输出是设计给人类阅读的,您不应该解析其输出

在 shell 脚本中,有一些情况下解析 ls 的输出可以是实现期望效果的最简单方法。由于 ls 可能会破坏文件名中的非 ASCII 和控制字符,因此这些情况是不需要从 ls 获取文件名的子集。

在 Python 中,绝对没有理由调用 ls。Python 具有所有 ls 的功能。使用os.listdir列出目录内容,使用os.statos 获取文件元数据。os 模块中的其他函数可能也与您的问题相关。


如果您正在通过 ssh 访问远程文件,则通过 sftp 列出文件名是相当健壮的方法:

echo ls -1 | sftp remote-site:dir

这将每行打印一个文件名,与ls实用程序不同,sftp不会损坏非可打印字符。您仍然无法可靠地列出文件名包含换行符的目录,但这很少做(将其记为潜在的安全问题而不是可用性问题)。

在Python中(请注意,需要转义remote_dir中的shell元字符):

command_line = "echo ls -1 | sftp " + remote_site + ":" + remote_dir
remote_files = os.popen(command_line).read().split("\n")

如需进行更复杂的交互,请在文档中查找sftp的批处理模式。

在某些系统上(Linux、Mac OS X,可能还有其他的Unix系统,但绝对不是Windows),另一种方法是通过ssh挂载远程文件系统,使用sshfs,然后在本地操作。


我通过SSH连接到远程机器。我发现没有办法在远程机器上执行像os.listdir这样的Python函数一行代码。因此,提出这个问题。我不想为仅列出文件编写脚本。有没有其他解决这个问题的方法? - fixxxer
@fixxxer: ssh确实改变了情况,这是你在初始问题中应该提及的事情!我认为sftp适合你的用例。 - Gilles 'SO- stop being evil'
对于混淆感到抱歉。我是否可以在“命令行”中插入密码的方式呢? - fixxxer
@fixxxer:我不知道,SSH的作者们不赞成明文存储密码,并且往往不会让这变得容易。你应该真正地设置基于密钥的身份验证(网络上有很多教程和http://superuser.com/上的问题与此相关)。 - Gilles 'SO- stop being evil'

11
你可以使用ls -1ls -l 也可以完成工作。

3
最佳答案已经提到了你所说的确切内容。此外,问题明确表示不应使用ls -l - DevX

10

你也可以使用ls -w1

这允许设置列的数量。 来自ls的manpage:

   -w, --width=COLS
          set output width to COLS.  0 means no limit

4
ls | tr "" "\n"

2

只要您的文件名不包含换行符,这个任务就很简单:

find . -maxdepth 1

如果你将这个命令管道传递到另一个命令中,你应该优先选择使用空字节来分隔文件名,而不是换行符,因为文件名中不能出现空字节(但可以有换行符):

find . -maxdepth 1 -print0

在终端上打印这个内容可能会显示为一行,因为通常不会打印空字节。一些程序可能需要特定的选项来处理以空字节分隔的输入,例如sort-z选项。您自己的脚本同样需要考虑到这一点。


1

-1开关是显而易见的方法,但值得一提的是,另一个选项是在双引号内使用echo命令替换,它保留了空格(这里是\n):

echo "$(ls)"

此外,如何使用ls命令的行为在这里中提到:

如果标准输出是终端,则输出按列(垂直排序)列出,并将控制字符输出为问号;否则,每行列出一个输出,并将控制字符原样输出。

现在你知道为什么重定向或管道输出一行一行地进行了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接