web-dev-qa-db-ja.com

lsに--zeroまたは-0オプションがない理由はありますか

この質問は、ls '-1オプションに関する質問と、lsの出力の処理を含む、質問と回答を求める傾向が繰り返し現れる傾向にあります。

この出力の再利用lsは理解できるようです。たとえば、lsを使用してファイルのリストを並べ替える方法を知っている場合は、出力を別の方法の入力として使用することができます。

これらのQ&Aに、適切に動作するファイル名(スペースや改行などの特殊文字は含まない)で構成されるファイル名リストへの参照が含まれていない場合、そこでコマンドシーケンスが機能しない危険性を指摘するコメントが頻繁に寄せられます。改行、スペースなどのファイルです.

findsort、およびその他のユーティリティは、「難しい」ファイル名を通信するという問題を解決します。 xargs Unix/Linuxファイルシステムでは、ファイル名の有効な文字ではないNUL文字/バイト(/?に加えて唯一の文字)でファイル名を区切るオプションを使用する。

lsのマニュアルページとls --helpの出力(より多くのオプションがリストされています)を調べたところ、lscoreutilsから)に指定するオプションがないことがわかりましたNULで区切られた出力。 「改行で区切られた出力ファイル名」)として解釈できる-1オプションがあります。

[〜#〜] q [〜#〜]lsに「NULで区切られたファイル名を出力する--zeroまたは-0オプションがない理由には、技術的または哲学的な理由がありますか? 「?

ファイル名のみを出力する(そして-lを使用しないなど)何かをする場合、それは理にかなっています:

ls -rt -0 | xargs -r0 …

私はこれが機能しない理由を欠落している可能性があります、または私が見落としたこの例の代替策がありますそしてそれはそれほど複雑ではなく、そして/または不明瞭ではありません


補遺:

ls -lrt -0を実行してもあまり意味がありませんが、find . -ls -print0を使用しない場合と同じように、-0/-z/--zeroオプションを指定しない理由にはなりません。

38
Timo

アップデート(2014-02-02)

私たち自身の @ Anthon's での決定 この機能の欠如に続いて のおかげで、この機能が欠けている理由について、もう少し正式な理由があります。前に説明しました:

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

パッチをありがとう。これを行う場合、これが使用するインターフェースです。ただし、lsは実際には人間が直接消費するためのツールであり、その場合、それ以上の処理はあまり役に立ちません。さらに処理するには、find(1)がより適しています。それは上のリンクの最初の回答でよく説明されています。

だから私はこれを追加することに対して70:30になるでしょう。

私の元の答え


これは私の個人的な意見ですが、lsを廃止することは設計上の決定だと思います。 findコマンドにこのスイッチがあることに気付いた場合:

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

このスイッチを外すことにより、デザイナーは、人間の消費以外の目的でls出力を使用してはならないことを示唆していました。他のツールによるダウンストリーム処理では、代わりにfindを使用する必要があります。

Findの使用方法

代わりの方法を探しているだけなら、ここにそれらのタイトルが付いています: それを正しく行う:簡単な要約 。そのリンクから、これらはおそらく3つのより一般的なパターンです:

  1. 単純なfind -exec; COMMANDが大きい場合は扱いにくく、1つのプロセス/ファイルを作成します。
    find . -exec COMMAND... {} \;
    
  2. +を使用した単純なfind -exec、COMMANDで複数のファイルが問題ない場合はより高速:
    find . -exec COMMAND... {} \+
    
  3. 検索とxargsを\ 0セパレータで使用

    (非標準の共通拡張-print0および-0。GNU、* BSD、busyboxで動作します)

    find . -print0 | xargs -0 COMMAND
    

さらなる証拠?

Joey Hessのブログからこのブログ投稿を見つけました: " ls:The missing options "。この投稿の興味深いコメントの1つ:

現時点で明らかな唯一の欠如は、-zオプションです。これにより、他のプログラムによる制約のために、出力ファイル名がNULLで終了するはずです。これは簡単に書くことができると思いますが、私はIRL(家具をたくさん動かすこと)で忙しく、それを理解できませんでした。それを書く人はいますか?

さらに検索したところ、Joeyのブログ投稿で言及されている追加スイッチの1つである「 新しい出力形式-j 」のコミットログでこれが見つかりました。 -zスイッチをlsに追加したことはありません。

他のオプションに関しては、複数の人が-eがほぼ有用であることに同意していますが、それを使用する理由を見つけることはできません。私のバグレポートでは、ls -eRは非常にバグが多いことを無視しています。 -jは明らかに冗談です。

参考文献

39
slm

@slmの回答が起源と考えられる理由に入るので、ここでは繰り返しません。そのようなオプションは、coreutils 拒否された機能のリスト ではではありませんですが、以下のパッチ is現在はPádraigBradyによって拒否されています coreutilsメーリングリストに送信した後。答えから明らかなように、これは哲学的な理由です(lsの出力は人間が消費するためのものです)。

そのようなオプションが自分にとって妥当であるかどうか試してみたい場合は、次のようにします。

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

次に、コミット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

別のmakeの後、次のようにテストできます。

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

そのため、パッチは機能し、機能しない理由はわかりませんが、それはオプションを除外する技術的理由がないことを証明するものではありません。 ls -R0はあまり意味をなさないかもしれませんが、lsがそのまま使用できるls -Rmも意味がありません。

20
Anthon

GNU xargs(coreutilsから))がある場合、次のコマンドを実行できます。

$ ls … |xargs -d "\n" …

それ以外の場合は、xargsのバージョンが-0をサポートしていることを確認した後(ほとんどはサポートしますが、 xargsのPOSIX仕様 はそれに言及していません)、次のコマンドを実行できます。

$ ls … |tr "\n" "\000" |xargs -0 …

私の~/.aliases~/.bashrcから入手した~/.zshrcファイルには、使用しているすべてのシステムに存在する(したがって、広範な互換性が必要です)には次のものが含まれます。

# Like `find ... -print0 |xargs -0` for programs that don't have a -print0
xargsn() {  # defer definition until first use
  if xargs --help 2>&1 |grep -Fqw "d, --delimiter"; then  # GNU
    xargsn() { xargs -d "\n" "$@"; }
  else
    # warning, xargs -0 isn't POSIX, but GNU, BSD/OSX, and Busybox support it
    xargsn() { tr "\n" "\000" |xargs -0 "$@"; }
  fi
  xargsn "$@"
}
if command -v compdef >/dev/null 2>&1; then compdef xargsn=xargs; fi # for zsh

これにより、xargsnを初めて実行するまでxargs --helpの呼び出しが延期され、(かなり長い)エイリアスファイルが高速化されます。つまり、GNU xargsをチェックします定義を設定した後(これは非常に高速で、約0.02秒)、最初の要求を1回限りの再帰呼び出しとして完了します。

その最後の行は、Z-Shellにxargsnをあたかもxargsであるかのように完了するように指示します(あるため)。

このxargsn関数は、改行を含む可能性のあるアイテムを繰り返し処理しない限り、どのコマンドでも機能します。警告:多くのファイルシステムのファイル名には、技術的に改行を含めることができます。このようなファイル名を使用している場合は、致命的な事態が発生しないようにしてください。 (「lsを解析しない」引数も参照してください。)

0
Adam Katz