Có lý do tại sao ls không có tùy chọn --zero hoặc -0


37

Câu hỏi này được nhắc nhở bởi các câu hỏi về tùy chọn ls' -1và xu hướng định kỳ của mọi người để đặt câu hỏi và câu trả lời bao gồm xử lý đầu ra của ls.

Việc sử dụng lại đầu ra này lscó vẻ dễ hiểu, ví dụ: nếu bạn biết cách sắp xếp danh sách các tệp với lsbạn có thể muốn sử dụng đầu ra theo cách đó làm đầu vào cho một thứ khác.

Nếu những câu hỏi và trả lời đó không bao gồm một tham chiếu đến danh sách tên tệp được tạo ra bao gồm các tên tệp hoạt động độc đáo (không có ký tự đặc biệt như dấu cách và dòng mới), chúng thường được nhận xét bởi ai đó chỉ ra sự nguy hiểm của chuỗi lệnh không hoạt động khi ở đó là các tập tin với dòng mới, không gian, vv

find, sortVà các tiện ích khác giải quyết vấn đề giao tiếp "khó khăn" tên tập tin để ví dụ xargsbằng cách sử dụng một tùy chọn để tách các tên tập tin với các ký tự NUL / byte mà không phải là một nhân vật hợp lệ trong tên tập tin (người duy nhất ngoài /?) Trên Hệ thống tập tin Unix / Linux.

Tôi đã tìm đến trang man cho lsvà đầu ra cho ls --help(có nhiều tùy chọn được liệt kê hơn) và không thể thấy rằng ls(từ coreutils) có một tùy chọn để chỉ định đầu ra tách biệt NUL. Nó có một -1tùy chọn có thể được hiểu là "tên tệp đầu ra được phân tách bằng dòng mới" )

H : Có lý do kỹ thuật hoặc triết học tại sao lskhông có tùy chọn --zerohoặc -0"tên tệp đầu ra được phân tách bằng NUL" không?

Nếu bạn làm một cái gì đó chỉ xuất ra tên tệp (và không sử dụng, ví dụ -l) có thể có ý nghĩa:

ls -rt -0 | xargs -r0 

Tôi có thể thiếu một cái gì đó tại sao điều này sẽ không hoạt động, hoặc có một sự thay thế cho ví dụ này mà tôi đã bỏ qua và nó không phức tạp và / hoặc tối nghĩa hơn nhiều .


Phụ lục:

Làm ls -lrt -0có lẽ không có ý nghĩa nhiều, nhưng trong cùng một cách mà find . -ls -print0không, vì vậy đó không phải là một lý do để không cung cấp một -0/ -z/ --zerotùy chọn.


Điều rõ ràng cần làm là viết và hỏi người bảo trì lõi GNU về suy nghĩ của anh ta về một lựa chọn như vậy.
Faheem Mitha

1
ls -rtzchắc chắn sẽ hữu ích Tương phản với lựa chọn thay thế: superuser.com/a/294164/21402
Tobu

Câu trả lời:


37

CẬP NHẬT (2014/02/02)

Nhờ có chúng tôi rất riêng @ Anthon của quyết tâm ở sau việc thiếu tính năng này lên , chúng ta có một lý do hơi trịnh trọng hơn là tại sao tính năng này được thiếu, mà nhắc lại những gì tôi đã giải thích trước đó:

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

Cảm ơn rất nhiều cho các bản vá. Nếu chúng ta làm điều này thì đây là giao diện chúng ta sẽ sử dụng. Tuy nhiên ls thực sự là một công cụ để con người tiêu thụ trực tiếp, và trong trường hợp đó, việc xử lý thêm sẽ ít hữu ích hơn. Để xử lý hơn nữa, tìm (1) là phù hợp hơn. Điều đó được mô tả tốt trong câu trả lời đầu tiên tại liên kết ở trên.

Vì vậy, tôi sẽ là 70:30 chống lại việc này.

Câu trả lời ban đầu của tôi


Đây là một chút quan điểm cá nhân của tôi nhưng tôi tin rằng đó là một quyết định thiết kế trong việc loại bỏ công tắc đó ls. Nếu bạn nhận thấy findlệnh không có công tắc này:

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

Bằng cách bỏ công tắc đó ra, các nhà thiết kế đã ám chỉ rằng bạn không nên sử dụng lsđầu ra cho bất cứ thứ gì ngoài tiêu dùng của con người. Để xử lý hạ nguồn bằng các công cụ khác, bạn nên sử dụng findthay thế.

Cách sử dụng tìm

Nếu bạn chỉ tìm kiếm các phương pháp thay thế, bạn có thể tìm thấy chúng ở đây, có tiêu đề: Thực hiện đúng: Tóm tắt nhanh . Từ liên kết đó có khả năng là 3 mẫu phổ biến hơn:

  1. Tìm đơn giản -exec; khó sử dụng nếu LỆNH lớn và tạo 1 tiến trình / tệp:
    find . -exec COMMAND... {} \;
  2. Tìm đơn giản -exec với +, nhanh hơn nếu nhiều tệp ổn đối với LỆNH:
    find . -exec COMMAND... {} \+
  3. Sử dụng find và xargs với dấu phân cách \ 0

    (các tiện ích mở rộng phổ biến không chuẩn -print0 và -0. Hoạt động trên GNU, * BSD, busybox)

    find . -print0 | xargs -0 COMMAND

Bằng chứng nữa?

Tôi tìm thấy bài đăng trên blog này từ blog của Joey Hess có tiêu đề: " ls: các tùy chọn còn thiếu ". Một trong những bình luận thú vị trong bài viết này:

Sự thiếu rõ ràng duy nhất bây giờ là một tùy chọn -z, điều này sẽ làm cho tên tệp đầu ra bị NULL chấm dứt vì sự kết hợp của các chương trình khác. Tôi nghĩ rằng điều này sẽ dễ viết, nhưng tôi đã rất bận rộn IRL (di chuyển nhiều đồ đạc) và đã không nhận được nó. Bất kỳ người nhận để viết nó?

Tìm kiếm thêm tôi đã tìm thấy điều này trong nhật ký cam kết từ một trong những công tắc bổ sung mà bài đăng trên blog của Joey đề cập, " định dạng đầu ra mới -j ", vì vậy có vẻ như bài đăng trên blog đã chọc vào khái niệm về việc thêm một -zcông tắc ls.

Đối với các tùy chọn khác, nhiều người đồng ý rằng -e gần như hữu ích, mặc dù không ai trong chúng ta hoàn toàn có thể tìm thấy lý do để sử dụng nó. Báo cáo lỗi của tôi đã bỏ qua đề cập rằng ls -eR rất có lỗi. -j rõ ràng là một trò đùa.

Tài liệu tham khảo


Cảm ơn bạn. Tôi nhận thức được sự cẩn thận. Không có câu hỏi nào về việc xử lý đầu ra ls hoàn tất mà không cần phải chỉ ra ;-)
Timo

@Timo - Tôi biết bạn làm, tôi đã làm nhiều hơn cho những độc giả tương lai của Q. Tôi thấy bạn trên trang web, rằng những thứ này sẽ xuất hiện trong các tìm kiếm của bạn bây giờ 8-)
slm

Tôi nhận ra rằng, và tốt là bạn đã làm. Tôi nên bao gồm các tài liệu tham khảo về lý do tại sao không (ít nhất là cho đến khi -0được thực hiện) trong câu hỏi của tôi, để không dẫn mọi người đi lạc đường.
Timo

Tất nhiên, giả sử không có bất kỳ thứ gì thực sự kỳ lạ như '\ n' trong tên tệp, ls -1 | tr '\012' '\000'sẽ liệt kê các tệp được phân tách bằng các ký tự NULL.
samiam

2
Bài viết này đi sâu vào các vấn đề về tên tệp
slm

20

Vì câu trả lời của @ slm đi vào nguồn gốc và những lý do có thể tôi sẽ không nhắc lại ở đây. Một tùy chọn như vậy là không trên coreutils từ chối danh sách tính năng , nhưng các bản vá dưới đây được tại từ chối bởi Padraig Brady sau khi gửi nó vào coreutils danh sách gửi thư. Từ câu trả lời, rõ ràng đây là một lý do triết học ( lsđầu ra là cho tiêu dùng của con người).

Nếu bạn muốn thử nếu một tùy chọn như vậy là hợp lý cho chính mình, hãy làm:

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

sau đó áp dụng bản vá sau với cam kết 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

Sau khi làm cho bạn có thể kiểm tra nó với:

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

Vì vậy, bản vá không hoạt động và tôi không thể thấy lý do tại sao nó không hoạt động, nhưng đó không phải là bằng chứng kỹ thuật để loại bỏ tùy chọn này. ls -R0có thể không có ý nghĩa nhiều, nhưng cũng như thế ls -Rmlscó thể làm ra khỏi hộp.


-z--zerophù hợp hơn với sắp xếp (cũng trong coreutils.
Anthon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.