引用された回答は引き続き表示されます。このリンク明確に述べる「解析しないでくださいls
!」これが私を悩ませる理由は次のとおりです。
そのリンクの情報は何の問題もなく大量に受け入れられるようですが、軽く読みながら少なくともいくつかのエラーを見つけることができます。
そのリンクに記載されている問題も解決策を探しているという欲求を引き起こさないようです。
最初の段落から:
...
[ls]
ファイルのリストを要求すると大きな問題があります。 Unix では、空白、改行、カンマ、パイプ記号、ファイル名として使用したいほとんどすべての文字を含む、ファイル名にほぼすべての文字を使用できます。 NUL 以外の区切り文字です。 ...ls
改行でファイル名を区切ります。ファイル名に改行文字が含まれるまでは問題ありません。ls
改行文字の代わりにNUL文字でファイル名を終了できる実装がわからないためls
。
本当に迷惑なことですか?どのように一度改行を含む可能性があるデータに対して、改行で終わるリストされたデータセットを処理できますか?さて、このサイトの質問に答える人が毎日これをやらなかったら、おそらく私たちは問題に陥ったと思います。
しかし、実際には、ほとんどの実装はls
出力を解析するための非常に単純なAPIを提供し、私たちはそれを認識することなく常にこれを行います。ファイル名をnullで終わることができるだけでなく、nullまたは必要な任意の文字列で始めることもできます。さらに、これらのランダムな文字列を割り当てることもできます。ファイルタイプ別。以下を考慮してください。
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
ループとglobを使用してください。
for f in *; do
[[ -e $f ]] || continue
...
done
作家はそう呼ぶ無効なファイル名ls
シェルグローバル変数を含むファイル名のリストを返す場合それからファイルリストを検索するには、Shell globを使用することをお勧めします!
以下を考慮してください。
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のすべてのインスタンスを疑問符('?'
)文字で強制的に作成します。実装は、出力が端末装置で構成されている場合、デフォルトでこのオプションを提供できます(MAY)。
-1
-(最初。)1行に1つの項目として出力するようにします。
ワイルドカードには固有の問題があります?
。どの文字なので、?
リスト内の複数の一致は同じファイルと複数回一致します。これは扱いやすいです。
これを行う方法は重要ではありませんが、最終的に行うことはあまりありません。以下に説明します。私が興味を持っているものは何ですか?なぜできないの。私の考えでは、この質問に対する最良の答えは受け入れられることです。人々に彼らが知っていることを知らせることに集中することをお勧めします。できる彼らがすることよりすることできません。少なくともあなたが間違っていることが証明される可能性ははるかに少ないと思います。
しかし、なぜ試してみますか?もちろん、私の主な動機は、他の人が私にできないと言ったことでした。ls
何を見つけるべきかを知る限り、結果は必要に応じて規則的で予測可能であることが非常に明らかです。エラーメッセージはほとんどのものよりも私を迷惑にさせます。
しかし、問題はPatrickとWumpus Qを除いてそうです。ウォームリーの答え(後者は素晴らしいハンドルを持っていますが)私はここにある答えのほとんどの情報がほとんど正しいと思います。シェルglobは、現在のディレクトリを検索するときに解析するよりも使いやすく、一般的に効率的ですls
。しかし、少なくとも私の考えでは、上記の記事で引用された誤った情報を広めることを正当化するのに十分ではなく、「受け取ることができる理由」でもありません。解析されていませんls
。」
zsh
Patrickの答えで一貫性のない結果は、主にthenを使用した結果ですbash
。 - デフォルトでは - 単語分割コマンドの結果はzsh
移植可能な方法で置き換えられません。だから彼が尋ねたとき$(
)
残りのファイルはどこに行きましたか?この質問に対する答えはあなたの殻はそれらを食べます。これが、移植可能なシェルコードで作業するときにこの変数を設定する必要がある理由ですSH_WORD_SPLIT
。zsh
私は彼の答えでこれを言及していないことは非常に誤解を招くと思います。
Wumpusの答えは私には適していませんでした。リストコンテキストの?
役割はいシェルボール。何を言うべきかわかりません。
複数の結果を処理するには、globの欲を制限する必要があります。以下は、ひどいファイル名のテストライブラリを作成して表示します。
{ 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 つだけが順番にエクスポートされるため、/
以下を使用すると、各項目のすべてのディレクトリ項目情報を含む、繰り返し、安定して区切られたファイルのリストを簡単に取得できます。次のように何ができるかを想像してください。
#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
最後に、より簡単な方法があります。分析するls
私はinode番号が必要なときにこれをよく使用します:
ls -1iq | grep -o '^ *[0-9]*'
これは、別の便利なPOSIX関連オプションであるinode番号のみを返します。
ベストアンサー1
私はこれをまったく信じていません。しかし、議論のためにあなたが仮定しましょうできる、十分な努力を傾ける準備ができていれば、ls
「敵対者」(あなたが書いたコードを知って意図的にコードを破損するように設計されたファイル名を選択した人)に対しても出力を安定的に解析できます。
こうすることはできても、これはまだ良い考えではありません。。
Bourne Shell 1はひどい言語です。極端な移植性が他の要因よりも重要でない限り、複雑なものには使用しないでくださいautoconf
。
ls
解析された出力がシェルスクリプトへの抵抗が最も少ないパスであるように見える問題がある場合、これは現在実行中の操作が次のようになるという強力な表示です。シェルスクリプトが複雑すぎるPerl、Python、Julia、または他の言語でコンテンツ全体を書き換える必要があります。いいね使いやすいスクリプト言語。デモとして、これはPythonで書いた最後のプログラムです:
import os, sys
for subdir, dirs, files in os.walk("."):
for f in dirs + files:
ino = os.lstat(os.path.join(subdir, f)).st_ino
sys.stdout.write("%d %s %s\n" % (ino, subdir, f))
ファイル名に異常な文字があっても問題ありません。出力は、出力がls
あいまいではないようにあいまいではありません。しかし、これは結果が直接使用される「実際の」プログラム(これらのデモとは対照的に)では重要ではありませんos.path.join(subdir, f)
。
また、作成したものとは異なり、これから6ヶ月経ってもまだ意味があり、少し異なる操作を実行する必要があるときに簡単に修正できることも重要です。たとえば、ドットファイルとエディタのバックアップを除いて、すべてを基本名に基づいてアルファベット順に処理する必要があるとします。
import os, sys
filelist = []
for subdir, dirs, files in os.walk("."):
for f in dirs + files:
if f[0] == '.' or f[-1] == '~': continue
lstat = os.lstat(os.path.join(subdir, f))
filelist.append((f, subdir, lstat.st_ino))
filelist.sort(key = lambda x: x[0])
for f, subdir, ino in filelist:
sys.stdout.write("%d %s %s\n" % (ino, subdir, f))
1はい、Bourne シェルの拡張バージョンは今すぐ使いやすく、bash
すべてzsh
元のバージョンよりはるかに優れています。コア「シェルユーティリティ」(find、grepなど)のGNU拡張も多くの役に立ちます。しかし、すべての拡張にもかかわらず、シェル環境は改善されません十分実際に良いスクリプト言語と競合するには、どのシェルについて話していても、「複雑な操作を実行するためにシェルを使用しないでください」というアドバイスが残ります。
「良いスクリプト言語でも良いインタラクティブシェルはどのようなものですか?」は、インタラクティブCLIに必要な利便性(例:代わりに入力を許可する)とcc -c -g -O2 -o foo.o foo.c
複雑subprocess.run(["cc", "-c", "-g", "-O2", "-o", "foo.o", "foo.c"])
なスクリプトエラーの微妙さ(例:いいえ任意の位置にある引用符でない単語を文字列リテラルとして解釈します。このようなものをデザインしようとすると、おそらくIPython、PowerShell、Luaを最初にBlenderに投げます。しかし、結果がどのように出てくるのか分からない。