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

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

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

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

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

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

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

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

 ls -rt -0 | xargs -r0 … 

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


Приложение:

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

ОБНОВЛЕНИЕ (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 вместо этого.

Способы использования

Если вы ищете альтернативные методы, вы можете найти их здесь, под названием « Правильное выполнение: быстрое резюме» . Из этой ссылки это, скорее всего, еще три распространенных шаблона:

  1. Простой find -exec; громоздкий, если COMMAND большой, и создает 1 процесс / файл:
     find . -exec COMMAND... {} \; 
  2. Простой find -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 .

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

Рекомендации

  • Почему вы не должны разбирать вывод ls (1)
  • Как я могу получить разрешения файла (или другие метаданные) без разбора ls -l вывода?
  • Имена файлов и имена путей в оболочке: как это сделать правильно

Поскольку ответы @ slm уходят в истоки и возможные причины, я не буду повторять это здесь. Такой вариант не относится к списку функций, отвергнутых coreutils, но патч ниже теперь отклонен Pádraig Brady после отправки его в список рассылки coreutils. Из ответа ясно, что это философская причина (выход для человеческого потребления).

Если вы хотите попробовать, подходит ли такой вариант для себя, выполните следующие действия:

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

затем примените следующий патч к commit b938b6e289ef78815935ffa705673a6a8b2ee98edd 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 eg "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.cb/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 abc > out || fail=1 +/bin/echo -en "a\00b\00c\00" > exp +compare exp out || fail=1 + +rm -rf out exp +ls -rt --zero abc > 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 может делать из коробки.