Czy istnieje powód, dla którego ls nie ma opcji --zero lub -0

37

To pytanie został poproszony przez pytania o ls" -1opcji i powtarzanego skłonności ludzi do zadawania pytań i odpowiedzi, które obejmuje przetwarzanie danych wyjściowych ls.

Ponowne wykorzystanie danych wyjściowych lswydaje się zrozumiałe, np .: jeśli wiesz, jak posortować listę plików, lsmożesz użyć danych wyjściowych w ten sposób jako danych wejściowych do czegoś innego.

Jeśli te pytania i odpowiedzi nie zawierają odniesienia do utworzonej listy nazw plików składającej się z ładnie zachowujących się nazw plików (bez znaków specjalnych, takich jak spacje i znaki nowej linii), często komentuje je ktoś, kto wskazuje na niebezpieczeństwo, że sekwencja poleceń nie będzie działać to pliki z nowymi liniami, spacjami itp.

find, sorta inne narzędzia rozwiązują problem przekazywania „trudnych” nazw plików np. xargspoprzez użycie opcji oddzielania nazw plików znakiem / bajtem NUL, który nie jest prawidłowym znakiem w nazwie pliku (jedyny oprócz /?) na Systemy plików Unix / Linux.

Szukałem strony podręcznika użytkownika dla lsi danych wyjściowych dla ls --help(który zawiera więcej opcji na liście) i nie mogłem znaleźć, że ls(od coreutils) ma opcję określania danych wyjściowych oddzielonych od NUL. Ma -1opcję, którą można interpretować jako „nazwy plików wyjściowych oddzielone znakiem nowej linii” )

P : Czy istnieje techniczny lub filozoficzny powód, dla którego lsnie ma opcji --zerolub -0, która „wyprowadzałaby nazwy plików rozdzielone przez NUL”?

Jeśli zrobisz coś, co wyświetla tylko nazwy plików (a nie używasz np. -l), Może to mieć sens:

ls -rt -0 | xargs -r0 

Mogłem przegapić coś, dlaczego to nie zadziałało, lub czy istnieje alternatywa dla tego przykładu, którą przeoczyłem i która nie jest o wiele bardziej skomplikowana i / lub niejasna .


Uzupełnienie:

Robienie tego ls -lrt -0prawdopodobnie nie ma większego sensu, ale w ten sam sposób, w jaki find . -ls -print0nie, dlatego nie jest to powód, aby nie udostępniać opcji -0/ -z/ --zero.

Timo
źródło
Oczywiste jest, aby napisać i zapytać opiekuna GNU coreutils, jakie są jego myśli na temat takiej opcji.
Faheem Mitha
1
ls -rtzna pewno by się przydał. Porównaj alternatywę: superuser.com/a/294164/21402
Tobu

Odpowiedzi:

37

AKTUALIZACJA (02.02.2014)

Dzięki naszej determinacji @ Anthon w śledzeniu braku tej funkcji , mamy nieco bardziej formalny powód, dla którego brakuje tej funkcji, co przypomina to, co wyjaśniłem wcześniej:

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

Wielkie dzięki za łatkę. Gdybyśmy to zrobili, to byłby to interfejs, którego byśmy użyli. Jednak ls jest tak naprawdę narzędziem do bezpośredniego spożycia przez człowieka, w takim przypadku dalsze przetwarzanie jest mniej przydatne. W przypadku dalszego przetwarzania funkcja find (1) jest bardziej odpowiednia. Jest to dobrze opisane w pierwszej odpowiedzi pod powyższym linkiem.

Byłbym więc 70:30 przeciwko dodaniu tego.

Moja oryginalna odpowiedź


To trochę moja osobista opinia, ale uważam, że decyzja o rezygnacji z tej opcji jest decyzją projektową ls. Jeśli zauważysz, że findpolecenie ma ten przełącznik:

-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.

Rezygnując z tego przełącznika, projektanci sugerowali, że nie powinieneś wykorzystywać lsprodukcji do celów innych niż spożycie przez ludzi. Do dalszego przetwarzania przez inne narzędzia powinieneś użyć findzamiast tego.

Sposoby użycia find

Jeśli szukasz tylko alternatywnych metod, możesz je tutaj znaleźć, zatytułowane: Robienie tego poprawnie: Szybkie podsumowanie . Z tego łącza są to prawdopodobnie 3 bardziej powszechne wzorce:

  1. Proste wyszukiwanie -exec; nieporęczny, jeśli COMMAND jest duży i tworzy 1 proces / plik:
    find . -exec COMMAND... {} \;
  2. Proste wyszukiwanie -exec z +, szybciej, jeśli wiele plików jest w porządku dla POLECENIA:
    find . -exec COMMAND... {} \+
  3. Używaj find i xargs z separatorami \ 0

    (niestandardowe rozszerzenia wspólne --print0 i -0. Działa na GNU, * BSD, busybox)

    find . -print0 | xargs -0 COMMAND

Dalsze dowody?

Znalazłem ten post z bloga na blogu Joeya Hessa zatytułowany: „ ls: brakujące opcje ”. Jeden z interesujących komentarzy w tym poście:

Jedynym oczywistym brakiem jest teraz opcja -z, która powinna sprawić, że wyjściowe nazwy plików będą NULL zakończone z powodu przerwania przez inne programy. Myślę, że byłoby to łatwe do napisania, ale byłem bardzo zajęty IRL (przenoszenie wielu mebli) i nie dostałem się do tego. Czy ktoś chce to napisać?

Podczas dalszych poszukiwań znalazłem to w dziennikach zatwierdzania jednego z dodatkowych przełączników, o których wspomina post na blogu Joeya, „ nowy format wyjściowy -j ”, więc wydaje się, że post na blogu wyśmiewał się na myśl o dodaniu -zprzełącznika ls.

Jeśli chodzi o inne opcje, wiele osób zgadza się, że -e jest prawie przydatne, chociaż żaden z nas nie może znaleźć powodu, aby z niego skorzystać. Mój raport o błędach nie wspomniał, że ls -eR jest bardzo wadliwy. -j to wyraźnie żart.

Referencje

slm
źródło
Dziękuję Ci. Mam świadomość zastrzeżeń. Żadne pytanie dotyczące przetwarzania wyjściowego ls nie jest kompletne bez uprzedzenia ;-)
Timo
@ Timo - Wiem, że tak, robiłem więcej dla przyszłych czytelników tego pytania. Widzę cię na stronie, że pojawiłyby się one w twoich wyszukiwaniach 8-)
slm
Zrozumiałem to i dobrze, że to zrobiłeś. Powinienem był zamieścić -0w swoim pytaniu odniesienia do tego, dlaczego nie (przynajmniej nie do momentu wdrożenia), aby nie zmylić ludzi.
Timo
Oczywiście, zakładając, że w nazwie pliku nie ma nic tak egzotycznego, jak „\ n”, ls -1 | tr '\012' '\000'wyświetli listę plików oddzielonych znakami NULL.
samiam
2
Ten artykuł omawia problemy związane z nazwami plików: dwheeler.com/essays/fixing-unix-linux-filenames.html
slm
20

Ponieważ odpowiedzi @ slm sięgają początków i możliwych powodów, nie powtórzę tego tutaj. Takiej opcji nie ma na liście odrzuconych coreutils , ale poniższa łatka jest teraz odrzucana przez Pádraiga Brady'ego po wysłaniu jej na listę mailingową coreutils. Z odpowiedzi jasno wynika, że ​​jest to powód filozoficzny ( lsprodukcja przeznaczona jest do spożycia przez ludzi).

Jeśli chcesz wypróbować, czy taka opcja jest dla Ciebie uzasadniona, wykonaj:

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

następnie zastosuj następującą łatkę przeciwko zatwierdzeniu b938b6e289ef78815935ffa705673a6a8b2ee98e dd 29.01.2014:

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

Po kolejnej wersji możesz to przetestować za pomocą:

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

Tak więc łatka działa i nie widzę powodu, dla którego by nie działała, ale to nie jest dowód, że nie ma technicznego powodu, aby pominąć tę opcję. ls -R0może nie mieć większego sensu, ale nie robi tego, ls -Rmco lsmożna zrobić po wyjęciu z pudełka.

Anthon
źródło
Posiadanie -zi --zerojest bardziej zgodne z sortowaniem (także w coreutils.
Anthon