私は一貫して引用の回答を参照このリンクを明確に述べ、「解析はいけませんのls
!」これにはいくつかの理由があります。
そのリンクの情報は、ささいな質問なしに大々的に受け入れられているように見えますが、偶然の読書で少なくともいくつかのエラーを見つけることができます。
また、あたかもそのリンクに記載されている問題が解決策を見つけたいという欲求を引き起こしていないかのようです。
最初の段落から:
...
[ls]
ファイルのリストを要求すると、大きな問題があります。Unixでは、空白、改行、コンマ、パイプ記号など、ほとんどすべての文字をファイル名に使用できます。 NULを除く区切り文字。...ls
ファイル名を改行で区切ります。これは、名前に改行を含むファイルが作成されるまで問題ありません。そして、ls
改行の代わりにNUL文字でファイル名を終了できるようにする実装がわからないため、これを使用してファイル名のリストを安全に取得できなくなりますls
。
残念ですよね?どのようにこれまで私たちは、改行は改行が含まれている可能性のあるデータにリストされているデータセットを終了扱うことができますか?まあ、このウェブサイトの質問に答える人々が日常的にこの種のことをしなかったなら、私たちは何らかのトラブルにあったと思うかもしれません。
ただし、ls
実際には、ほとんどの実装では、出力を解析するための非常に単純なAPIが実際に提供されており、私たちはみな、気づかずにそれをずっと行ってきました。ファイル名をnullで終了できるだけでなく、nullで開始することも、他の任意の文字列で開始することもできます。さらに、これらの任意の文字列をfile-typeごとに割り当てることができます。考えてください:
LS_COLORS='lc=\0:rc=:ec=\0\0\0:fi=:di=:' ls -l --color=always | cat -A
total 4$
drwxr-xr-x 1 mikeserv mikeserv 0 Jul 10 01:05 ^@^@^@^@dir^@^@^@/$
-rw-r--r-- 1 mikeserv mikeserv 4 Jul 10 02:18 ^@file1^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 01:08 ^@file2^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 02:27 ^@new$
line$
file^@^@^@$
^@
詳細はこちらをご覧ください。
さて、この記事の次の部分で、本当に私を魅了します。
$ ls -l
total 8
-rw-r----- 1 lhunath lhunath 19 Mar 27 10:47 a
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a?newline
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a space
問題は、の出力から、
ls
あなたもコンピュータもファイルのどの部分がファイル名を構成しているかを判断できないことです。それはそれぞれの言葉ですか?いいえ。各行ですか?いいえ。この質問に対する正しい答えはありません。わかりません。また、どのように注意してください
ls
我々の場合には、それがなって(あなたのファイル名のデータを文字化け時々\n
単語の間に文字を「」と 「改行」に?疑問符 ......
現在のディレクトリ内のすべてのファイルを繰り返し処理する場合は、
for
ループとグロブを使用します。
for f in *; do
[[ -e $f ]] || continue
...
done
作成者は、シェルグロブを含むファイル名のリストを返すときにファイル名を文字化ls
けし、シェルグロブを使用してファイルリストを取得することをお勧めします!
以下を考慮してください。
printf 'touch ./"%b"\n' "file\nname" "f i l e n a m e" |
. /dev/stdin
ls -1q
f i l e n a m e
file?name
IFS="
" ; printf "'%s'\n" $(ls -1q)
'f i l e n a m e'
'file
name'
POSIXは、オペランド-1
と-q
ls
オペランドを次のように定義します。
-q
-印刷できないファイル名文字と<tab>
sの各インスタンスを強制的に疑問符('?'
)文字として書き込みます。出力が端末デバイスに対するものである場合、実装はデフォルトでこのオプションを提供します。
-1
- (数字1)。1行に1つのエントリを強制的に出力します。
-グロブは、独自の問題がないわけではない?
試合どんなので、複数の一致文字?
リストの結果が同じファイルを複数回マッチします。それは簡単に処理できます。
このことをどのように行うかはポイントではありません-結局のところ、それほど多くのことをする必要はなく、以下に示されています-私はなぜそうでないことに興味がありました。私が考えているように、その質問に対する最良の答えは受け入れられました。できないことよりも、できることを伝えることに重点を置くことをお勧めします。私が思うに、あなたは少なくとも間違っていると証明される可能性ははるかに低いです。
しかし、なぜ試してみるのでしょうか?確かに、私の主な動機は、他の人が私にできないと私に言い続けたことでした。私はそれを非常によく知っているls
あなたはあまりにも長い間、あなたが何を探すべきか知っているとして、それを望むことができるように、出力が定期的かつ予測可能なようです。誤報は、ほとんどのことよりも私を悩ませます。
しかし真実は、パトリックとWumpus Q. Wumbleyの両方の顕著な例外を除いて(後者の素晴らしいハンドルにもかかわらず)、ここでの答えのほとんどの情報はほとんど正しいと思います-シェルグロブはどちらもより使いやすいですそして一般に、構文解析よりも現在のディレクトリの検索に関してより効果的ls
です。彼らは、少なくとも私に関しては、しかし、上記の記事で引用された誤った情報を伝播するいずれか正当化するのに十分な理由ではないも彼らがする許容正当化されている「パースことはありませんls
。」
パトリックの答えの一貫性のない結果は、ほとんどが彼がzsh
then を使用した結果であることに注意してくださいbash
。zsh
-デフォルト- $(
置換されたコマンドをワード分割しない)
で、移植可能な方法で結果を返します。それで、彼が残りのファイルはどこに行ったのかと尋ねると?その質問への答えは、あなたのシェルがそれらを食べたということです。これが、移植性のあるシェルコードをSH_WORD_SPLIT
使用zsh
して処理するときに変数を設定する必要がある理由です。私は彼の答えでこれを指摘しなかったことが、ひどく誤解を招くと考えています。
Wumpusの答えは私にとっては計算されません-リストコンテキストでは、?
文字はシェルグロブです。他にそれを言う方法がわかりません。
複数の結果のケースを処理するには、グロブの貪欲さを制限する必要があります。以下は、ひどいファイル名のテストベースを作成して表示するだけです:
{ printf %b $(printf \\%04o `seq 0 127`) |
sed "/[^[-b]*/s///g
s/\(.\)\(.\)/touch '?\v\2' '\1\t\2' '\1\n\2'\n/g" |
. /dev/stdin
echo '`ls` ?QUOTED `-m` COMMA,SEP'
ls -qm
echo ; echo 'NOW LITERAL - COMMA,SEP'
ls -m | cat
( set -- * ; printf "\nFILE COUNT: %s\n" $# )
}
出力
`ls` ?QUOTED `-m` COMMA,SEP
??\, ??^, ??`, ??b, [?\, [?\, ]?^, ]?^, _?`, _?`, a?b, a?b
NOW LITERAL - COMMA,SEP
?
\, ?
^, ?
`, ?
b, [ \, [
\, ] ^, ]
^, _ `, _
`, a b, a
b
FILE COUNT: 12
今、私よ安全ではないすべての文字/slash
、-dash
、:colon
その後、シェルグロブ内、または英数字の文字sort -u
のユニークな結果を得るためのリスト。これは安全です。なぜなら、ls
印刷できない文字はすでに私たちのために守られているからです。見る:
for f in $(
ls -1q |
sed 's|[^-:/[:alnum:]]|[!-\\:[:alnum:]]|g' |
sort -u | {
echo 'PRE-GLOB:' >&2
tee /dev/fd/2
printf '\nPOST-GLOB:\n' >&2
}
) ; do
printf "FILE #$((i=i+1)): '%s'\n" "$f"
done
出力:
PRE-GLOB:
[!-\:[:alnum:]][!-\:[:alnum:]][!-\:[:alnum:]]
[!-\:[:alnum:]][!-\:[:alnum:]]b
a[!-\:[:alnum:]]b
POST-GLOB:
FILE #1: '?
\'
FILE #2: '?
^'
FILE #3: '?
`'
FILE #4: '[ \'
FILE #5: '[
\'
FILE #6: '] ^'
FILE #7: ']
^'
FILE #8: '_ `'
FILE #9: '_
`'
FILE #10: '?
b'
FILE #11: 'a b'
FILE #12: 'a
b'
以下で問題に再度アプローチしますが、別の方法論を使用します。\0
null 以外に、/
ASCII文字がパス名で禁止されている唯一のバイトであることに注意してください。ここにglobを置いておき、代わりにPOSIXで指定された-d
オプションとのためにls
POSIXで指定された-exec $cmd {} +
コンストラクトを組み合わせますfind
。順番にfind
1つしか自然に出力されないため/
、以下は、すべてのエントリのすべてのdentry情報を含む再帰的で確実に区切られたファイルリストを簡単に取得します。次のようなことで何ができるか想像してみてください。
#v#note: to do this fully portably substitute an actual newline \#v#
#v#for 'n' for the first sed invocation#v#
cd ..
find ././ -exec ls -1ldin {} + |
sed -e '\| *\./\./|{s||\n.///|;i///' -e \} |
sed 'N;s|\(\n\)///|///\1|;$s|$|///|;P;D'
###OUTPUT
152398 drwxr-xr-x 1 1000 1000 72 Jun 24 14:49
.///testls///
152399 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
\///
152402 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
^///
152405 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
`///
...
ls -i
特に結果の一意性に問題がある場合は、非常に便利です。
ls -1iq |
sed '/ .*/s///;s/^/-inum /;$!s/$/ -o /' |
tr -d '\n' |
xargs find
これらは、私が考えることができる最もポータブルな手段です。GNU ls
でできること:
ls --quoting-style=WORD
最後に、iノード番号が必要なときにたまたま頻繁に使用する、はるかに簡単な解析ls
方法を示します。
ls -1iq | grep -o '^ *[0-9]*'
これはinode番号を返すだけです-これは別の便利なPOSIX指定オプションです。
stat
、各ファイルが存在することを実際にチェックするため、私が答えで使用した理由です。sed
事の一番下にあるあなたのビットは機能しません。
ls
は、最初の場所で単に解析しないよりも簡単または簡単、または何らかの方法で優れているのでしょうか?あなたが説明していることは非常に難しいです。すべてを理解するために分解する必要があり、私は比較的有能なユーザーです。平均的なジョーがこのようなものに対処できるとは期待できないでしょう。
ls
出力の解析が間違っている理由はすべて、元のリンク(および他の多くの場所)で十分に説明されています。OPがそれを理解するのを助けを求めているなら、この質問は合理的でしたが、代わりにOPは単に彼の間違った使い方がOKであることを証明しようとしています。
parsing ls is bad
。こうfor something in $(command)
して正確な結果を得るために、単語分割に頼ることは、大多数のために悪いですcommand's
、単純な出力を持ちません。
time bash -c 'for i in {1..1000}; do ls -R &>/dev/null; done'
= 3.18s vstime bash -c 'for i in {1..1000}; do echo **/* >/dev/null; done'
= 1.28s