ls没有--zero或-0选项是有原因的吗


37

这个问题是由有关ls' -1选项' 和人们反复提出问题的倾向的问题引起的,包括处理...的输出ls

对输出的这种重用ls似乎是可以理解的,例如:如果您知道如何对文件列表进行排序,则ls可能希望以这种方式将输出用作其他输入。

如果这些问与答不包括对由良好表现的文件名组成的文件名列表的引用(没有空格和换行符之类的特殊字符),则通常会有人指出它们,指出存在该命令序列不起作用的危险是带有换行符,空格等的文件。

findsort和其他实用程序解决通信“困难”的文件名如问题xargs通过选项的文件名与NUL字符/字节这是不是在文件名中的合法字符分隔(唯一一个除/?)上Unix / Linux文件系统。

我查看了手册页,ls并找到的输出ls --help(列出了更多选项),但找不到ls(来自coreutils)有一个选项来指定NUL分隔的输出。它确实有一个-1选项,可以解释为“用换行符分隔的输出文件名”

:是否有技术或哲学上的原因,为什么ls没有一个“ --zero或” -0选项会“输出以NUL分隔的文件名”?

如果您执行的操作仅输出文件名(而不使用eg -l),那么可能会有意义:

ls -rt -0 | xargs -r0 

我可能会遗漏一些为什么它不起作用的原因,或者这个示例是否有我忽略的替代方法,它没有那么复杂和/或晦涩难懂


附录:

这样做ls -lrt -0可能没有多大意义,但在以同样的方式find . -ls -print0不对,所以这不是一个理由不提供-0/ -z/ --zero选项。


显而易见的事情是编写并询问GNU coreutils维护者对这种选择的看法。
Faheem Mitha 2014年

1
ls -rtz肯定会有用。对比其他方法:superuser.com/a/294164/21402
Tobu 2015年

Answers:


37

更新(2014-02-02)

由于我们自己的@Anthon决定不提供此功能,因此对于缺少该功能的原因,我们有一个更为正式的理由,这重申了我之前的解释:

Re: [PATCH] ls: adding --zero/-z option, including tests

From:      Pádraig Brady
Subject:   Re: [PATCH] ls: adding --zero/-z option, including tests
Date:      Mon, 03 Feb 2014 15:27:31 +0000

非常感谢您的补丁。如果要执行此操作,则将使用此接口。但是,ls实际上是人类直接消费的工具,在这种情况下,进一步处理的用处不大。对于进一步处理,find(1)更适合。在以上链接的第一个答案中对此进行了很好的描述。

因此,我反对70:30的添加。

我的原始答案


这是我个人的看法,但我认为这是决定放弃开关的设计决定ls。如果您注意到该find命令确实具有此开关:

-print0
      True; print the full file name on the standard output, followed by a 
      null character (instead of the newline character that -print uses).  
      This allows file  names  that  contain  newlines or other types of white 
      space to be correctly interpreted by programs that process the find 
      output.  This option corresponds to the -0 option of xargs.

通过省略该开关,设计人员意味着您不应将ls输出用于人类消费以外的其他用途。对于其他工具进行的下游处理,应find改为使用。

查找方式

如果您只是在寻找替代方法,可以在这里找到它们,标题为:正确执行:快速摘要。通过该链接,这些可能是3种更常见的模式:

  1. 简单查找-exec; 如果COMMAND大,则不方便,并创建1个进程/文件:
    find . -exec COMMAND... {} \;
  2. 使用+简单查找-exec,如果可以使用COMMAND多个文件,则速度更快:
    find . -exec COMMAND... {} \+
  3. 将find和xargs与\ 0分隔符一起使用

    (非标准通用扩展名-print0和-0。适用于GNU,* BSD,busybox)

    find . -print0 | xargs -0 COMMAND

进一步的证据?

我从Joey Hess的博客中找到了该博客文章,标题为“ ls:缺少的选项 ”。这篇文章中有趣的评论之一:

现在唯一明显的不足是-z选项,该选项应使输出文件名以NULL终止,以供其他程序使用。我认为这很容易编写,但是我一直很忙于IRL(移动很多家具),却没有去做。有读者要写吗?

进一步搜索之后,我在Joey的博客文章中提到的其他开关之一的提交日志中找到了这一点,即“ 新输出格式-j ”,因此,似乎该博客文章很喜欢在上添加一个-z开关ls

至于其他选择,很多人都同意-e几乎是有用的,尽管我们没人能找到使用它的理由。我的错误报告忽略了提及ls -eR的问题。-j显然是个玩笑。

参考文献


谢谢。我知道这些警告。没有指出,关于ls输出处理的问题就没有完成;-)
Timo 2014年

@Timo-我知道你愿意,我正在为这个问题的未来读者做更多的事情。我在网站上看到你,这些问题现在会在你的搜索中出现8)
slm

我意识到了,很高兴您做到了。我应该-0在我的问题中提到为什么不这样做(至少直到实施之前),以免导致人们误入歧途。
2014年

当然,假设文件名中没有像“ \ n”这样的东西,ls -1 | tr '\012' '\000'它将列出以NULL字符分隔的文件。
samiam'2

2
本文深入探讨文件命名问题:dwheeler.com/essays/fixing-unix-linux-filenames.html
slm

20

由于@slm的答案来自起源和可能的原因,因此在此不再赘述。这样的选择是不是对的coreutils 否决功能列表,但低于该补丁 现在哈灵顿布雷迪拒绝将其发送到coreutils的邮件列表之后。从答案中可以明显看出,这是一个哲学原因(ls产出是供人类消费的)。

如果您想尝试这种选择是否适合自己,请执行以下操作:

git clone git://git.sv.gnu.org/coreutils
cd coreutils
./bootstrap
./configure
make

然后对提交b938b6e289ef78815935ffa705673a6a8b2ee98e dd 2014-01-29应用以下补丁:

From 6413d5e2a488ecadb8b988c802fe0a5e5cb7d8f4 Mon Sep 17 00:00:00 2001
From: Anthon van der Neut <address@hidden>
Date: Mon, 3 Feb 2014 15:33:50 +0100
Subject: [PATCH] ls: adding --zero/-z option, including tests

* src/ls.c has the necessary changes to allow -z/--zero option to be
  specified, resulting in a NUL seperated list of files. This
  allows the output of e.g. "ls -rtz" to be piped into other programs

* tests/ls/no-args.sh was extended to test the -z option

* test/ls/rt-zero.sh was added to test both the long and short option
  together with "-t"

This patch was inspired by numerous questions on unix.stackexchange.com
where the output of ls was piped into some other program, invariably
resulting in someone pointing out that is an unsafe practise because of
possible newlines and other characters in the filenames.
---
 src/ls.c            |   31 +++++++++++++++++++++++++------
 tests/ls/no-arg.sh  |    7 ++++++-
 tests/ls/rt-zero.sh |   38 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 7 deletions(-)
 create mode 100755 tests/ls/rt-zero.sh

diff --git a/src/ls.c b/src/ls.c
index 5d87dd3..962e6bb 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -381,6 +381,7 @@ static int file_size_width;
    many_per_line for just names, many per line, sorted vertically.
    horizontal for just names, many per line, sorted horizontally.
    with_commas for just names, many per line, separated by commas.
+   with_zero for just names, one per line, separated by NUL.

-l (and other options that imply -l), -1, -C, -x and -m control

    this parameter.  */
@@ -391,7 +392,8 @@ enum format
     one_per_line,              /* -1 */
     many_per_line,             /* -C */
     horizontal,                        /* -x */
-    with_commas                        /* -m */
+    with_commas,               /* -m */
+    with_zero,                 /* -z */
   };

static enum format format;

@@ -842,6 +844,7 @@ static struct option const long_options[] =
   {"block-size", required_argument, NULL, BLOCK_SIZE_OPTION},
   {"context", no_argument, 0, 'Z'},
   {"author", no_argument, NULL, AUTHOR_OPTION},
+  {"zero", no_argument, NULL, 'z'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -850,12 +853,12 @@ static struct option const long_options[] =
 static char const *const format_args[] =
 {
   "verbose", "long", "commas", "horizontal", "across",
-  "vertical", "single-column", NULL
+  "vertical", "single-column", "zero", NULL
 };
 static enum format const format_types[] =
 {
   long_format, long_format, with_commas, horizontal, horizontal,
-  many_per_line, one_per_line
+  many_per_line, one_per_line, with_zero
 };
 ARGMATCH_VERIFY (format_args, format_types);

@@ -1645,7 +1648,7 @@ decode_switches (int argc, char **argv)

     {
       int oi = -1;
       int c = getopt_long (argc, argv,
-                           "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1",
+                           "abcdfghiklmnopqrstuvw:xzABCDFGHI:LNQRST:UXZ1",
                            long_options, &oi);
       if (c == -1)
         break;
@@ -1852,6 +1855,10 @@ decode_switches (int argc, char **argv)
             format = one_per_line;
           break;

+ case 'z':

+          format = with_zero;
+          break;
+
         case AUTHOR_OPTION:
           print_author = true;
           break;
@@ -2607,7 +2614,8 @@ print_dir (char const *name, char const *realname, bool 
command_line_arg)
                  ls uses constant memory while processing the entries of
                  this directory.  Useful when there are many (millions)
                  of entries in a directory.  */
-              if (format == one_per_line && sort_type == sort_none
+              if ((format == one_per_line || format == with_zero)
+                      && sort_type == sort_none
                       && !print_block_size && !recursive)
                 {
                   /* We must call sort_files in spite of
@@ -3598,6 +3606,14 @@ print_current_files (void)
         }
       break;

+ case with_zero:

+      for (i = 0; i < cwd_n_used; i++)
+        {
+          print_file_name_and_frills (sorted_file[i], 0);
+          putchar ('\0');
+        }
+      break;
+
     case many_per_line:
       print_many_per_line ();
       break;
@@ -4490,6 +4506,7 @@ print_many_per_line (void)
           indent (pos + name_length, pos + max_name_length);
           pos += max_name_length;
         }
+      putchar ('X'); // AvdN
       putchar ('\n');
     }
 }
@@ -4780,7 +4797,8 @@ Sort entries alphabetically if none of -cftuvSUX nor 
--sort is specified.\n\
   -F, --classify             append indicator (one of */=>@|) to entries\n\
       --file-type            likewise, except do not append '*'\n\
       --format=WORD          across -x, commas -m, horizontal -x, long -l,\n\
-                               single-column -1, verbose -l, vertical -C\n\
+                               single-column -1, verbose -l, vertical -C,\n\
+                               zeros -z\n\
       --full-time            like -l --time-style=full-iso\n\
 "), stdout);
       fputs (_("\
@@ -4888,6 +4906,7 @@ Sort entries alphabetically if none of -cftuvSUX nor 
--sort is specified.\n\
   -X                         sort alphabetically by entry extension\n\
   -Z, --context              print any security context of each file\n\
   -1                         list one file per line\n\
+  -z, --zero                 list files separated with NUL\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
diff --git a/tests/ls/no-arg.sh b/tests/ls/no-arg.sh
index e356a29..da28b96 100755
--- a/tests/ls/no-arg.sh
+++ b/tests/ls/no-arg.sh
@@ -30,11 +30,16 @@ out
 symlink
 EOF

-

 ls -1 > out || fail=1

compare exp out || fail=1 +/bin/echo -en "dir\00exp\00out\00symlink\00" > exp || framework_failure_

+
+ls --zero > out || fail=1
+
+compare exp out || fail=1
+
 cat > exp <<\EOF
 .:
 dir
diff --git a/tests/ls/rt-zero.sh b/tests/ls/rt-zero.sh
new file mode 100755
index 0000000..cdbd311
--- /dev/null
+++ b/tests/ls/rt-zero.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Make sure name is used as secondary key when sorting on mtime or ctime.
+
+# Copyright (C) 1998-2014 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls touch
+
+date=1998-01-15
+
+touch -d "$date" c || framework_failure_
+touch -d "$date" a || framework_failure_
+touch -d "$date" b || framework_failure_
+
+
+ls -zt a b c > out || fail=1
+/bin/echo -en "a\00b\00c\00" > exp
+compare exp out || fail=1
+
+rm -rf out exp
+ls -rt --zero a b c > out || fail=1
+/bin/echo -en "c\00b\00a\00" > exp
+compare exp out || fail=1
+
+Exit $fail
--
1.7.9.5

接连进行,您可以使用以下命令进行测试:

  src/ls -rtz | xargs -0 -n1 src/ls -ld

因此,该补丁确实可以正常工作,我看不出为什么它不起作用的原因,但这不能证明没有技术上的理由可以放弃该选件。ls -R0可能没有多大意义,但也没有ls -Rm哪个ls能做到开箱即用。


拥有-z--zero更符合排序线(也的coreutils。
安森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.