Y a-t-il une raison pour laquelle ls n'a pas d'option --zero ou -0

37

Cette question a été motivée par des questions sur lsl' -1option et la tendance récurrente des gens à poser des questions et des réponses incluant le traitement de la sortie de ls.

Cette réutilisation de la sortie lssemble compréhensible, par exemple: si vous savez trier une liste de fichiers avec, lsvous voudrez peut-être utiliser la sortie de cette manière comme entrée pour autre chose.

Si ces questions-réponses n'incluent pas de référence à la liste de noms de fichiers générée, composée de noms de fichiers au comportement agréable (pas de caractères spéciaux tels que des espaces et des nouvelles lignes), elles sont souvent commentées par quelqu'un soulignant le danger que la séquence de commandes ne fonctionne pas lorsque sont des fichiers avec des nouvelles lignes, des espaces, etc.

find, sortEt d' autres services publics résoudre le problème de la communication des noms de fichiers « difficiles » à , par exemple xargsen utilisant une option pour séparer les noms de fichiers avec le caractère NUL / octet qui n'est pas un caractère valide dans le nom de fichier (le seul en plus /?) Sur Systèmes de fichiers Unix / Linux.

J'ai consulté la page de manuel lset la sortie ls --help(qui contient plus d'options) et je n'ai pas trouvé que ls(de coreutils) dispose d'une option permettant de spécifier une sortie séparée NUL. Il a une -1option qui peut être interprétée comme "les noms de fichiers de sortie séparés par une nouvelle ligne" )

Q : Y a-t-il une raison technique ou philosophique pour laquelle lsaucune option --zeroou -0option permettant de "sortir les noms de fichiers séparés par NUL"?

Si vous faites quelque chose qui ne sort que les noms de fichiers (sans utiliser par exemple -l), cela pourrait avoir un sens:

ls -rt -0 | xargs -r0 

Il se peut que je manque quelque chose pour expliquer pourquoi cela ne fonctionnerait pas, ou existe-t-il une alternative à cet exemple que j'ai oubliée et qui n'est pas beaucoup plus compliquée et / ou obscure .


Addenda:

Faire ls -lrt -0n'a probablement pas beaucoup de sens, mais de la même manière, ce find . -ls -print0n'est donc pas une raison pour ne pas fournir une option -0/ -z/ --zero.

Timo
la source
La chose évidente à faire est d’écrire et de demander au mainteneur de GNU coreutils ce qu’il pense de cette option.
Faheem Mitha
1
ls -rtzserait certainement utile. Contrastez l'alternative: superuser.com/a/294164/21402
Tobu

Réponses:

37

MISE À JOUR (2014-02-02)

Merci à notre propre @ Anthon de la détermination à la suite de l'absence de cette fonctionnalité en place , nous avons une raison un peu plus formel pour expliquer pourquoi cette fonctionnalité fait défaut, qui rappelle ce que je l' ai expliqué plus tôt:

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

Merci beaucoup pour le patch. Si nous devions faire cela, c'est l'interface que nous utiliserions. Cependant, ls est vraiment un outil de consommation directe par un humain, et dans ce cas, un traitement ultérieur est moins utile. Pour un traitement ultérieur, find (1) est plus adapté. Cela est bien décrit dans la première réponse au lien ci-dessus.

Donc, je serais 70:30 contre l'ajout de cela.

Ma réponse originale


C’est un peu mon opinion personnelle, mais j’estime que c’est une décision de conception de laisser ce changement de côté ls. Si vous remarquez que la findcommande a ce commutateur:

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

En laissant ce commutateur inactif, les concepteurs ont laissé entendre que vous ne devriez pas utiliser la lssortie pour autre chose que la consommation humaine. Pour le traitement en aval par d'autres outils, vous devriez plutôt utiliser find.

Façons d'utiliser find

Si vous recherchez simplement des méthodes alternatives, vous pouvez les trouver ici, intitulé: Le faire correctement: résumé rapide . A partir de ce lien, ce sont probablement les 3 modèles les plus courants:

  1. Recherche simple -exec; peu maniable si la commande est grande et crée 1 processus / fichier:
    find . -exec COMMAND... {} \;
  2. Recherche simple -exec avec +, plus rapide si plusieurs fichiers sont acceptables pour COMMAND:
    find . -exec COMMAND... {} \+
  3. Utilisez find et xargs avec \ 0 separators

    (extensions communes non standard -print0 et -0. Fonctionne sur GNU, * BSD, busybox)

    find . -print0 | xargs -0 COMMAND

Une preuve supplémentaire?

J'ai trouvé cet article du blog de Joey Hess intitulé: " ls: les options manquantes ". Un des commentaires intéressants dans ce post:

Le seul manque évident à l’heure actuelle est une option -z, qui devrait faire en sorte que les noms de fichiers en sortie soient terminés par NULL pour être utilisés par d’autres programmes. Je pense que ce serait facile à écrire, mais j’ai été extrêmement occupé par IRL (déplacer beaucoup de meubles) et je n’y suis pas parvenu. Des preneurs pour l'écrire?

En outre la recherche J'ai trouvé dans le commettras journaux de l' un des commutateurs supplémentaires que le poste de blog de Joey mentionne, « nouveau format de sortie -j », il semblerait que le billet de blog a été moquait à l'idée de ne jamais ajouter un -zinterrupteur à ls.

En ce qui concerne les autres options, de nombreuses personnes s'accordent pour dire que -e est presque presque utile, même si aucun d'entre nous ne peut vraiment trouver une raison de l'utiliser. Mon rapport de bogue a négligé de mentionner que ls -eR est très bogué. -j est clairement une blague.

Les références

slm
la source
Merci. Je suis conscient des mises en garde. Aucune question sur le traitement de la sortie de ls n'est complète sans l'avoir signalée ;-)
Timo
@Timo - Je sais que vous le faites, j'en faisais davantage pour les futurs lecteurs de ce Q. Q. Je vous vois sur le site, ils seraient déjà
apparus
Je m'en suis rendu compte et c'est bien que vous l'ayez fait. J'aurais dû inclure des références à pourquoi pas (du moins jusqu'à ce qu'il -0soit mis en œuvre) dans ma question, afin de ne pas égarer les gens.
Timo le
Bien sûr, en supposant qu’il n’y ait rien de vraiment exotique comme un "\ n" dans un nom de fichier, la ls -1 | tr '\012' '\000'liste des fichiers sera séparée par des caractères NULL.
Samiam
2
Cet article va au fond des problèmes de nom de fichier: dwheeler.com/essays/fixing-unix-linux-filenames.html
slm
20

Comme les réponses de @ slm vont dans les origines et les raisons possibles, je ne répéterai pas cela ici. Une telle option ne figure pas sur la liste des fonctionnalités rejetées par coreutils , mais le correctif ci - dessous est maintenant rejeté par Pádraig Brady après l’avoir envoyé sur la liste de diffusion coreutils. La réponse indique clairement qu'il s'agit d'une raison philosophique (le lsrésultat est destiné à la consommation humaine).

Si vous voulez essayer si une telle option est raisonnable pour vous, faites:

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

puis appliquez le correctif suivant contre 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

Après une autre marque, vous pouvez le tester avec:

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

Le correctif fonctionne donc et je ne vois pas pourquoi il ne fonctionnerait pas, mais ce n’est pas la preuve qu’il n’ya aucune raison technique de laisser de côté cette option. ls -R0n’a peut-être pas beaucoup de sens, mais ce ls -Rmqui ne lspeut pas le faire en dehors de la boîte.

Anthon
la source
Avoir -zet --zeroest plus en ligne avec le genre (également en coreutils.
Anthon