Есть ли причина, по которой у ls нет опции --zero или -0?

37

Этот вопрос был вызван вопросами о ls« -1опциях» и повторяющейся тенденцией людей задавать вопросы и ответы, включая обработку результатов ls.

Такое повторное использование выходных данных lsкажется понятным, например: если вы знаете, как сортировать список файлов ls, возможно, вы захотите использовать выходные данные таким образом в качестве входных данных для чего-то другого.

Если эти вопросы и ответы не включают ссылку на список имен файлов, составленный из имен файлов с хорошим поведением (без специальных символов, таких как пробелы и символы новой строки), они часто комментируются кем-то, указывающим на опасность того, что последовательность команд не работает, когда файлы с переводом строки, пробелами и т. д.

find, sortИ другие коммунальные услуги решить проблему общения «сложные» имена файлов Е.Г. xargs, используя опцию для разделения имен файлов с NUL символ / байт , который не является допустимым символом в имени файла (единственный в дополнение к /?) На Файловые системы Unix / Linux.

Я посмотрел на справочную страницу для lsи вывод для ls --help(который имеет больше перечисленных опций) и не смог найти, что ls(из coreutils) имеет возможность указать NUL-разделенный вывод. У него есть -1опция, которую можно интерпретировать как «имена выходных файлов, разделенные символом новой строки» )

В : Есть ли техническая или философская причина, почему lsнет опции --zeroили, -0которая бы "выводила имена файлов, разделенные NUL"?

Если вы делаете что-то, что выводит только имена файлов (а не использует, например -l), это может иметь смысл:

ls -rt -0 | xargs -r0 

Я мог бы что-то упустить, почему это не сработает, или есть альтернатива для этого примера, которую я упустил из виду, и которая не намного сложнее и / или неясна .


Приложение:

Выполнение, ls -lrt -0вероятно, не имеет большого смысла, но так же, как это find . -ls -print0не происходит, так что это не является причиной, чтобы не предоставлять параметр -0/ -z/ --zero.

Timo
источник
Очевидная вещь, которую нужно сделать, это написать и спросить сопровождающего GNU coreutils, что он думает о такой опции.
Фахим Митха
1
ls -rtzопределенно было бы полезно. Сравните альтернативу: superuser.com/a/294164/21402
Тобу

Ответы:

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

Еще одно доказательство?

Я нашел этот пост в блоге Джои Хесса под названием: « ls: пропущенные опции ». Один из интересных комментариев в этом посте:

Единственный очевидный недостаток в настоящее время - это опция -z, которая должна сделать выходные имена файлов равными NULL для завершения другими программами. Я думаю, что это было бы легко написать, но я был чрезвычайно занят IRL (перемещая много мебели) и не добирался до этого. Любые желающие написать это?

Дальнейший поиск Я нашел это в журналах коммитов от одного из дополнительных переключателей, который упоминается в сообщении блога Джои, « новый выходной формат -j », поэтому казалось, что сообщение блога высмеивало идею добавления -zпереключателя ls.

Что касается других вариантов, многие согласны с тем, что -e почти полезен, хотя никто из нас не может найти причину его использования. В моем отчете об ошибке не упоминалось, что ls -eR очень глючит. -j это явно шутка.

Ссылки

SLM
источник
Спасибо. Я осведомлен о предостережениях. Нет сомнений в том, что обработка вывода ls завершена без указания на это ;-)
Timo
@Timo - я знаю, что вы делаете, я делал больше для будущих читателей этого вопроса. Я вижу вас на сайте, чтобы они уже появлялись в ваших поисках 8-)
slm
Я понял это, и хорошо, что ты сделал. Я должен был включить ссылки на то, почему нет (по крайней мере, пока не -0будет реализовано) в моем вопросе, чтобы не вводить людей в заблуждение.
Тимо
Конечно, при условии, что в имени файла нет ничего необычного, например '\ n', ls -1 | tr '\012' '\000'будут перечислены файлы, разделенные символами NULL.
Самам
2
В этой статье идет в глубину проблемы именования файлов: dwheeler.com/essays/fixing-unix-linux-filenames.html
ОДС
20

Поскольку ответы @ slm уходят в истоки и возможные причины, я не буду повторять это здесь. Такой вариант не на Coreutils отклоненного список функций , но ниже патч в настоящее отвергнут Padraig Brady после отправки его в 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.
Anthon