C'è un motivo per cui ls non ha un'opzione --zero o -0


37

Questa domanda è stato richiesto dal domande su ls' -1opzione e la tendenza ricorrente di persone a chiedere domande e risposte che include l'elaborazione l'output di ls.

Questo riutilizzo dell'output lssembra comprensibile, ad esempio: se sai come ordinare un elenco di file ls, potresti voler utilizzare l'output in quel modo come input per qualcos'altro.

Se queste domande e risposte non includono un riferimento all'elenco dei nomi di file prodotto costituito da nomi di file ben comportati (nessun carattere speciale come spazi e righe), vengono spesso commentati da qualcuno che sottolinea il pericolo che la sequenza di comandi non funzioni quando sono file con newline, spazi ecc.

find, sortE altre utilità risolvere il problema di comunicare "difficili" i nomi dei file, ad esempio, xargsutilizzando la possibilità di separare i nomi dei file con il carattere NUL / byte che non è un carattere valido nel nome del file (l'unico in aggiunta a /?) Su File system Unix / Linux.

Ho cercato la pagina man lse l'output per ls --help(che ha più opzioni elencate) e non sono riuscito a trovare che ls(da coreutils) ha un'opzione per specificare l'output separato NUL. Ha -1un'opzione che può essere interpretata come "nomi di file di output separati da newline" )

D : Esistono motivi tecnici o filosofici per cui lsnon esiste un'opzione --zeroo -0che "generi nomi di file separati da NUL"?

Se fai qualcosa che genera solo i nomi dei file (e non usi ad es. -l) Che potrebbe avere senso:

ls -rt -0 | xargs -r0 

Potrei mancare qualcosa perché questo non funzionerebbe, o c'è un'alternativa per questo esempio che ho trascurato e che non è molto più complicato e / o oscuro .


Addendum:

Fare ls -lrt -0probabilmente non ha molto senso, ma allo stesso modo di find . -ls -print0no, quindi non è un motivo per non fornire un'opzione -0/ -z/ --zero.


La cosa ovvia da fare è scrivere e chiedere al manutentore di coreutils GNU quali sono i suoi pensieri su tale opzione.
Faheem Mitha,

1
ls -rtzsarebbe sicuramente utile. Contrasta l'alternativa: superuser.com/a/294164/21402
Tobu

Risposte:


37

AGGIORNAMENTO (2014-02-02)

Grazie alla determinazione di @ Anthon nel seguire la mancanza di questa funzionalità , abbiamo un motivo leggermente più formale sul perché questa funzione manchi, il che ribadisce ciò che ho spiegato in precedenza:

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

Grazie mille per la patch. Se dovessimo farlo, questa sarebbe l'interfaccia che utilizzeremmo. Tuttavia, è davvero uno strumento per il consumo diretto da parte di un essere umano, e in tal caso un'ulteriore elaborazione è meno utile. Per ulteriori elaborazioni, find (1) è più adatto. Questo è ben descritto nella prima risposta al link sopra.

Quindi sarei 70:30 contro l'aggiunta di questo.

La mia risposta originale


Questo è un po 'della mia opinione personale, ma credo che sia una decisione di progettazione nel lasciare quel passaggio fuori ls. Se noti che il findcomando ha questa opzione:

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

Lasciando questo interruttore, i progettisti hanno insinuato che non dovresti usare la lsproduzione per qualcosa di diverso dal consumo umano. Per l'elaborazione a valle con altri strumenti, dovresti findinvece utilizzare .

Modi per usare find

Se stai solo cercando i metodi alternativi, puoi trovarli qui, dal titolo: Farlo correttamente: un breve riepilogo . Da quel link sono probabilmente i 3 modelli più comuni:

  1. Trova semplice -exec; ingombrante se COMMAND è grande e crea 1 processo / file:
    find . -exec COMMAND... {} \;
  2. Semplice ricerca -exec con +, più veloce se più file sono a posto per COMMAND:
    find . -exec COMMAND... {} \+
  3. Usa find e xargs con \ 0 separatori

    (estensioni comuni non standard -print0 e -0. Funziona su GNU, * BSD, busybox)

    find . -print0 | xargs -0 COMMAND

Ulteriore evidenza?

Ho trovato questo post sul blog di Joey Hess intitolato " ls: the missing options ". Uno dei commenti interessanti in questo post:

L'unica ovvia mancanza ora è un'opzione -z, che dovrebbe rendere NULL i nomi dei file di output terminati per il consumo da altri programmi. Penso che sarebbe facile da scrivere, ma sono stato estremamente impegnato in IRL (spostando molti mobili) e non ci sono riuscito. Qualche acquirente per scriverlo?

Ulteriore ricerca ho trovato questo nei registri di commit da uno degli switch aggiuntivi che menziona il post sul blog di Joey, " nuovo formato di output -j ", quindi sembrerebbe che il post sul blog si stesse prendendo in giro l'idea di aggiungere mai uno -zswitch ls.

Per quanto riguarda le altre opzioni, più persone concordano sul fatto che -e è quasi utile, sebbene nessuno di noi possa trovare un motivo per usarlo. La mia segnalazione di bug ha trascurato di menzionare che ls -eR è molto difettoso. -j è chiaramente uno scherzo.

Riferimenti


Grazie. Sono consapevole delle avvertenze. Nessuna domanda sull'elaborazione dell'output è completa senza che sia stato sottolineato ;-)
Timo

@Timo - So che lo fai, stavo facendo di più per i futuri lettori di questo Q. Ti vedo sul sito, che questi sarebbero arrivati ​​nelle tue ricerche adesso Cool
slm

L'ho capito, e bene che tu l'abbia fatto. Avrei dovuto includere riferimenti al perché (almeno non fino -0all'attuazione) nella mia domanda, al fine di non smarrire le persone.
Timo,

Naturalmente, supponendo che non ci sia qualcosa di veramente esotico come una '\ n' in un nome file, ls -1 | tr '\012' '\000'elencherà i file separati da caratteri NULL.
Samiam,

2
Questo articolo approfondisce i problemi di denominazione dei file: dwheeler.com/essays/fixing-unix-linux-filenames.html
slm

20

Dato che le risposte di @ slm vanno alle origini e ai possibili motivi, non lo ripeterò qui. Tale opzione non si trova nell'elenco delle funzionalità rifiutate di coreutils , ma la patch di seguito viene ora rifiutata da Pádraig Brady dopo averla inviata alla mailing list di coreutils. Dalla risposta è chiaro che questa è una ragione filosofica (la lsproduzione è per il consumo umano).

Se vuoi provare se tale opzione è ragionevole per te, fai:

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

quindi applicare la seguente patch su commit 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

Dopo un'altra marca puoi provarlo con:

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

Quindi la patch funziona e non riesco a vedere un motivo per cui non lo farebbe, ma questa non è una prova che non c'è motivo tecnico per escludere l'opzione. ls -R0potrebbe non avere molto senso, ma nemmeno ciò ls -Rmche lspuò fare immediatamente.


Avere -zed --zeroè più in linea con l'ordinamento (anche in coreutils.
Anthon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.