【问题标题】:Bash: Get modified `ls`-like output (multiple entries per line)Bash:获取修改后的类似 ls 的输出(每行多个条目)
【发布时间】:2015-03-10 14:31:02
【问题描述】:

当您在命令行上调用 ls 而没有其他选项时,每行都会有多个条目。

人为的例子:

$ ls mydir/*.tar.gz
mydir/foo.tar.gz        mydir/bar.tar.gz        mydir/baz.tar.gz

但是如果你想以某种方式修改输出,你会得到每行一个条目:

$ ls mydir/*.tar.gz | sed "s/\.tar\.gz//g"
mydir/foo
mydir/bar
mydir/baz

有很多条目,这变得很麻烦——我想要多个对齐的列。

我试图想出类似于find mydir -name "*.tar.gz" -printf ...,或... -exec ...,甚至(yuk!)for file in $(find ...) 的东西,但我能想出的任何东西都让人觉得很不雅(想想反变量,取模,只是猜测终端宽度......)。

是否有一些优雅的方法可以在多列输出中获取几个文件名,例如在对它们进行修补后(例如 sedbasename 等)?

【问题讨论】:

  • 因为很容易漏掉:关键词是"after have tinkered with them",意思是分栏必须在laterafter修改ls 的输出,所以 ls 根据定义本身不能提供它。接受的答案说明了这一点(通过提供通用的分栏解决方案),而这里的其他答案包括如何让 ls itself 分栏。

标签: bash multiple-columns ls


【解决方案1】:

(令人惊讶的名字)column 命令会做你想做的事。

ls | column -c 80

这将在列中显示 80 宽显示的输出。您可能需要等待输出,因为它必须先确定项目的宽度,然后才能格式化任何内容。

它适用于任何命令。

您可以使用COLUMNS 环境变量查找列宽(这可能取决于您的shell - 键入set 以查看变量列表并计算出来),或使用tput cols 命令。

【讨论】:

  • 这看起来很有希望......有什么方法可以事先确定真实(当前)终端宽度?
【解决方案2】:

ls -C 强制多列输出,即使输出指向远离控制台。

【讨论】:

  • 不知何故这似乎变幻无常:使用真实世界的路径/文件名,当我调用ls -C 而不对输出做任何事情时,我将终端填充到全宽。一旦我在某处管道输出,它似乎假设一个小得多的终端窗口......如果后处理 shortens 每个条目,则不(不能)考虑。
【解决方案3】:

更新免责声明

  • 此答案不适用于 OP,因为他想先修改 ls 输出,然后然后 将其列成列;因此,必须在单独传递中应用列,稍后,这是accepted answer通过column -c <n>提供的。
  • 此答案仅在您想使用列式ls 输出原样时才有效。
    • 除此之外,它还提供了一些有趣的背景信息,说明ls 如何决定如何格式化其输出以及最大值。它假定的线宽。

rojomoke's promising answer 为基础,指出-C 明确请求ls 的多列输出:

tl;dr

模拟ls 的多列终端输出,当将内容发送到文件或通过管道使用当前终端的最大值. line width(单字符显示列数),使用COLUMNS=$(tput cols) ls -C;例如:

COLUMNS=$(tput cols) ls -C | cat  # `| cat` is an example command to show pipe behavior

显然,你也可以选择一个独立于当前终端的固定数字;例如,COLUMNS=120 ls -C ...

如果没有 COLUMNS=... 前缀,则基于最大值进行分列。 80的线宽,与终端窗口的实际宽度无关。


注意:以下内容部分是推测性的。如果我错了,请告诉我。

ls,当输出到终端时:

  • 默认生成柱状(多列)输出(隐含-C
  • 确定终端的最大值。线宽本身[1]

相比之下,当ls 的标准输出连接到管道或输出文件时,它

  • 默认为逐行输出(隐含-1
  • 当指定-C 时,它从COLUMNS 环境 变量(不是shell 变量)中获取线宽;如果没有这样的变量,则默认为80

bash shells 中,$COLUMNS 通常是一个 shell 变量,设置在 仅交互式 shell 中,而不是 环境 变量 -换句话说:$COLUMNS 已定义,但未导出

要让ls 尊重$COLUMNS 变量,您必须将其定义为环境 变量。

最简洁的方法是在ls 的调用前添加一个临时、命令本地环境变量定义(一般模式是:<envVar>=<value> <commmand> ...):

由于tput cols 返回当前终端的线宽,我们得到:

COLUMNS=$(tput cols) ls -C ...

tput cols 也适用于脚本,因此它是一种可靠的方法;以交互方式,看似毫无意义的命令COLUMNS=$COLUMNS ls -C 也可以工作。

注意ls 在输出到终端时甚至会尊重COLUMNS 环境变量。


[1] 也就是说,它不需要 环境变量COLUMNS,但如果定义了它,就会尊重它。请注意,名为 COLUMNS 的(未导出的)shell 变量(在交互式 shell 中是典型情况)被忽略

【讨论】:

  • 正如我对 rojomoke 的评论,这里固有的问题是格式化是在您修改输出之前 完成的。例如,如果修改是删除路径组件(使每个条目更短),您的输出将不会使用完整的终端宽度。如果修改对条目的长度进行了不规则更改,则输出将丢失格式。读起来很有趣,但 rghome 确定了我认为的解决方案。 ;-)
  • @DevSolar:你说得对 - 我错过了想要格式化 after 修改的部分。所以,rghome 的回答确实是正确的解决方案(尽管最后没关系,我很高兴他将find 命令更改为ls 以避免分心) - 我将添加免责声明我的回答并留下它,因为我也认为这种行为很有趣。
  • 带有免责声明,+1 了解详情。感谢您的宝贵时间。
  • @DevSolar:谢谢,我很感激。
猜你喜欢
  • 1970-01-01
  • 2014-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-19
  • 2011-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多