Apakah ada alasan mengapa ls tidak memiliki opsi --zero atau -0

37

Pertanyaan ini didorong oleh pertanyaan tentang opsi ls' -1dan kecenderungan berulang orang untuk bertanya dan menjawab yang mencakup pemrosesan keluaran dari ls.

Penggunaan kembali output ini lstampaknya dapat dimengerti, misalnya: jika Anda tahu cara mengurutkan daftar file dengan lsAnda mungkin ingin menggunakan output dengan cara itu sebagai input untuk sesuatu yang lain.

Jika Q&A tersebut tidak menyertakan referensi ke daftar nama file yang dihasilkan yang terdiri dari nama file berperilaku baik (tidak ada karakter khusus seperti spasi dan baris baru), mereka sering dikomentari oleh seseorang yang menunjukkan bahaya urutan perintah yang tidak berfungsi ketika ada adalah file dengan baris baru, spasi, dll.

find, sortdan utilitas lain menyelesaikan masalah mengkomunikasikan nama file "sulit" ke mis. xargsdengan menggunakan opsi untuk memisahkan nama file dengan NUL karakter / byte yang bukan karakter yang valid dalam nama file (satu-satunya selain /?) pada Sistem file Unix / Linux.

Saya melihat ke halaman lsmanual dan output untuk ls --help(yang memiliki lebih banyak opsi terdaftar) dan tidak dapat menemukan bahwa ls(dari coreutils) memiliki opsi untuk menentukan output yang dipisahkan oleh NUL. Itu memang memiliki -1opsi yang dapat diartikan sebagai "nama file keluaran dipisahkan oleh baris baru" )

T : Apakah ada alasan teknis atau filosofis mengapa lstidak memiliki --zeroatau -0opsi yang akan "menampilkan nama file yang dipisahkan oleh NUL"?

Jika Anda melakukan sesuatu yang hanya menampilkan nama file (dan tidak menggunakan mis. -l) Yang masuk akal:

ls -rt -0 | xargs -r0 

Saya bisa kehilangan sesuatu mengapa ini tidak berhasil, atau adakah alternatif untuk contoh ini yang saya abaikan dan yang tidak jauh lebih rumit dan / atau tidak jelas .


Tambahan:

Melakukan ls -lrt -0mungkin tidak masuk akal, tetapi dengan cara yang find . -ls -print0sama tidak, jadi itu bukan alasan untuk tidak memberikan opsi -0/ -z/ --zero.

Timo
sumber
Yang jelas harus dilakukan adalah menulis dan bertanya kepada pengelola GNU coreutils apa pendapatnya tentang opsi semacam itu.
Faheem Mitha
1
ls -rtzpasti akan bermanfaat. Bandingkan alternatifnya: superuser.com/a/294164/21402
Tobu

Jawaban:

37

UPDATE (2014-02-02)

Berkat tekad @ Anthon kami sendiri dalam mengikuti kekurangan fitur ini , kami memiliki alasan yang sedikit lebih formal mengapa fitur ini kurang, yang menegaskan kembali apa yang saya jelaskan sebelumnya:

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

Terima kasih banyak untuk tambalannya. Jika kita melakukan ini maka ini adalah antarmuka yang akan kita gunakan. Namun ls benar-benar alat untuk konsumsi langsung oleh manusia, dan dalam hal ini pemrosesan lebih lanjut kurang bermanfaat. Untuk pemrosesan lebih lanjut, cari (1) lebih cocok. Itu dijelaskan dengan baik dalam jawaban pertama di tautan di atas.

Jadi saya akan menolak untuk menambahkan ini 70:30.

Jawaban asli saya


Ini sedikit pendapat pribadi saya, tetapi saya yakin itu adalah keputusan desain untuk meninggalkan perubahan itu ls. Jika Anda perhatikan findperintah memiliki saklar ini:

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

Dengan meninggalkan peralihan itu, para desainer menyiratkan bahwa Anda tidak boleh menggunakan lsoutput untuk apa pun selain konsumsi manusia. Untuk pemrosesan hilir dengan alat lain, Anda harus menggunakan findsebagai gantinya.

Cara menggunakan find

Jika Anda hanya mencari metode alternatif, Anda dapat menemukannya di sini, berjudul: Melakukannya dengan benar: Ringkasan cepat . Dari tautan itu kemungkinan ada 3 pola yang lebih umum:

  1. Temukan sederhana -exec; berat jika PERINTAH besar, dan membuat 1 proses / file:
    find . -exec COMMAND... {} \;
  2. Temukan sederhana -exec dengan +, lebih cepat jika banyak file tidak masalah untuk PERINTAH:
    find . -exec COMMAND... {} \+
  3. Gunakan find dan xargs dengan pemisah \ 0

    (ekstensi umum tidak standar-print0 dan -0. Bekerja pada GNU, * BSDs, busybox)

    find . -print0 | xargs -0 COMMAND

Bukti lebih lanjut?

Saya menemukan posting blog ini dari blog Joey Hess berjudul: " ls: the missing options ". Salah satu komentar menarik dalam posting ini:

Satu-satunya kekurangan jelas sekarang adalah opsi -z, yang seharusnya membuat nama file keluaran dihentikan NULL untuk konsumsi oleh program lain. Saya pikir ini akan mudah untuk ditulis, tetapi saya sudah sangat sibuk IRL (memindahkan banyak furnitur) dan tidak sampai ke sana. Adakah yang mau menuliskannya?

Pencarian lebih lanjut saya menemukan ini di log komit dari salah satu switch tambahan yang posting blog Joey menyebutkan, " format output -j baru ", sehingga tampaknya posting blog itu mengolok-olok gagasan pernah menambahkan -zberalih ke ls.

Mengenai opsi-opsi lain, banyak orang setuju bahwa -e hampir hampir berguna, walaupun tidak ada di antara kita yang bisa menemukan alasan untuk menggunakannya. Laporan bug saya lalai menyebutkan bahwa ls -eR sangat bermasalah. -j jelas lelucon.

Referensi

slm
sumber
Terima kasih. Saya menyadari peringatan. Tidak ada pertanyaan tentang pemrosesan output ls lengkap tanpa menunjukkan hal itu ;-)
Timo
@Timo - Saya tahu Anda tahu, saya melakukan lebih banyak untuk pembaca masa depan dari Q. Saya melihat Anda di situs ini, bahwa ini akan muncul dalam pencarian Anda sekarang 8-)
slm
Saya menyadari itu, dan bagus yang Anda lakukan. Saya harus memasukkan referensi mengapa tidak (setidaknya tidak sampai -0diimplementasikan) dalam pertanyaan saya, agar tidak membuat orang tersesat.
Timo
Tentu saja, dengan asumsi tidak ada sesuatu yang benar-benar eksotis seperti '\ n' dalam nama file, ls -1 | tr '\012' '\000'akan mencantumkan file yang dipisahkan oleh karakter NULL.
samiam
2
Artikel ini masuk ke kedalaman masalah nama file
slm
20

Sebagai jawaban @ slm masuk ke asal-usul dan kemungkinan alasan saya tidak akan mengulanginya di sini. Opsi semacam itu tidak ada pada daftar fitur coreutils yang ditolak , tetapi tambalan di bawah ini sekarang ditolak oleh Pádraig Brady setelah mengirimkannya ke mailing list coreutils. Dari jawaban itu jelas ini adalah alasan filosofis ( lsoutput untuk konsumsi manusia).

Jika Anda ingin mencoba jika opsi semacam itu masuk akal untuk Anda sendiri, lakukan:

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

kemudian terapkan tambalan berikut terhadap 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

Setelah dibuat lagi, Anda dapat mengujinya dengan:

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

Jadi tambalan itu berfungsi dan saya tidak bisa melihat alasan mengapa tidak, tapi itu bukan bukti tidak ada alasan teknis untuk meninggalkan opsi. ls -R0mungkin tidak masuk akal, tetapi tidak juga ls -Rmyang lsbisa dilakukan di luar kotak.

Anthon
sumber
Memiliki -zdan --zerolebih sesuai dengan sort (juga dalam coreutils.
Anthon