grepを使用してls出力をフィルタリングすると予期しない結果が発生する

grepを使用してls出力をフィルタリングすると予期しない結果が発生する

現在grep問題を使用して解決していますls。目的は、リンクされたファイルである現在のディレクトリのすべての行を一覧表示することです。私のディレクトリには3つのリンクファイルがありますが、コマンドを実行すると1つだけが表示されます。

私が入力する内容は次のとおりです。

ls -lR | grep l*

どんな助けでも大変感謝します。ありがとう

答え1

@NasirRileyが正しい道を進んでいます。現在のディレクトリのシンボリックリンクを一覧表示するには、find . -mindepth 1 -maxdepth 1 -type l.testを実行します。

$ cd "$(mktemp --directory)"
$ mkdir foo
$ touch foo/bar baz
$ ln --symbolic foo/bar ban
$ ln --symbolic bar foo/bat # symlink in subdirectory, should be ignored
$ find . -mindepth 1 -maxdepth 1 -type l
./ban

答え2

パイプにはいくつかの問題があります。

  1. 出力の解析ls これは良い考えではありません。(あなたも見ることができますなぜ`ls`を解析しないのですか*(そしてどうすればいいですか?))。その形式は標準化されておらず、ファイル名にはNULと/。多くの場合、与えられた例には改行文字が含まれます。 (ls別の方法で呼び出すと、あいまいな可能性がある他の結果が発生する可能性があります。)

    $ touch 'foo
    > bar'
    $ ls -1
    'foo'$'\n''bar'
    $ ls | cat
    foo
    bar
    

    foo2つの異なるファイルがあるか、bar同じファイル名の2つの部分がありますか?

    特定の種類のファイルをディレクトリから再帰的に検索する安全な方法は次のとおりです。find

  2. エスケープされていない文字列は、l*シェルで次のように解釈されます。ワイルドカード表現する。広範なファイル名のリストを介して拡張されます。「文書」の定義l)は現在のディレクトリから始まります。

    # In a directory you created for testing purposes
    $ rm *; touch foo; ln -s foo link1; ln -s foo link2; ln -s foo link3
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep link1 link2 link3
    

    シェルxtraceオプション(つまりset -x、複数のシェルで利用可能です。POSIX)は、ファイル名拡張(グローバル)の効果を表示するのに役立ちます。つまり、文字列がl*拡張され、link1 link2 link3の内容からgrep(シンボリックリンクおよび経由で)検索されます。 (link1foolink2link3grep検索するパターンの後にファイル名のリストが指定されている場合、標準入力は読み込まれません。

    あなたが持っているなら一つ名前が次から始まるファイルl:

    # In a directory you created for testing purposes
    $ rm *; touch foo; ln -s foo link1; ln -s foo Link2; ln -s foo Link3
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep link1
    lrwxrwxrwx 1 user group 3 May  1 03:04 link1 -> foo
    

    次に、grep標準入力(の出力)からここの行に一致する文字列をls検索します。 (ファイル名が指定されていない場合、またはファイル名引数が指定されている場合は、link1標準入力読み取りが行われます)。grep-

    あなたはする必要があります引用するシェルがファイル名拡張を実行しないように、リテラル文字列が引数として渡されます。あるいは、シェルがサポートしている場合set -f

  3. 現在のディレクトリにで始まるファイル名がない場合、ワイルドカード式は変更されず、l最初の場所引数として渡されます。これは正規表現として解釈されます(デフォルトはgrepgrepBREバリアント)その内容は、「すべての入力行に対して次のように一致します。任意に選択できる l(どこでも)」は次の項目と効果的に一致します。

    # In a directory you created for testing purposes
    $ rm *; touch foo
    $ ls -lR
    .:
    total 0
    -rw-r--r-- 1 user group 0 May  1 02:49 foo
    $ set -x; ls -lR | grep l*
    + ls -lR
    + grep 'l*'
    .:
    total 0
    -rw-r--r-- 1 user group 0 May  1 03:14 foo
    

    テキストで始まる文字列を一致させるには、lアンカー式が必要ですgrep '^l'

答え3

ご存知のように、探しているコマンドは次のとおりです。

ls -l | grep '^l'

引用符は必ずしも必要ではありません。

ディレクトリツリーではなく現在のディレクトリが欲しいと指定したので、-Ronオプションを削除してください。ls

どちらにしても、あなたが指摘した答えはfindおそらくより良い解決策でしょう。

関連情報