ファイル名のスペースの問題


8

ファイルのリストで何かを繰り返したいのですが。問題のファイルの名前にはスペースが含まれています。

david@david: ls -l
total 32
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha
-rw-rw-r-- 1 david david  0 Mai  8 11:55 haha~
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (3rd copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (4th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (5th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (6th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (7th copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (another copy)
-rw-rw-r-- 1 david david 13 Mai  8 11:55 haha (copy)

次に、これらの各ファイルをstatしたいと思います。

david@david: echo '
for file in $(ls)
do
stat $file
done' | bash

(複数行のコマンドを記述するために、エコーとパイプを使用します。)

それを行うと、名前にスペースが含まれていないファイルで正しく機能します。しかし、他の...

stat: cannot stat ‘(another’: No such file or directory
stat: cannot stat ‘copy)’: No such file or directory

変更$(ls)"$(ls)"$file"$file"ない作品。私に何ができる?

編集:

echo '
for files in *
do
stat "$files"
done' | bash

トリックを行います!私はbashを初めて使用するので、できるだけ簡単にしたいので、スペースをエスケープしxargsたり、を使用したり、で解決しread -rたりしても、問題は解決します。

一部の人が尋ねたように:はい、代わりにこれを使用するのstat *は奇妙です。しかし、forループを使用して、bash内の一連のファイル名に同じコマンドを適用する一般的な方法を見つけたかっただけです。そうstatするために立つことができgzipgpgまたはrm


1
何が問題なのstat *ですか?(;-)
Rmano


例としてstatを使用しています。:) lsを使用してファイル名を収集し、lsの結果をbashループで使用します。
user258532

回答:


12

からの複数引用echo 'は事態を複雑にしています。

あなたはただ使うことができます:

for f in *; do stat -- "$f"; done

だけでなく

stat -- * 

...そしてファイルを収集してからコマンドを適用する場合は(なぜですか?)続行できます(ただし、新しい行を含むファイルには注意してください...(1))

for f in *; do echo "$f"; done | xargs stat --

...そして隠しファイルも必要な場合は、パターンとして使用* .*...ますが、それを覚えておくセットになります。

余談ですがls出力を解析しないください


(1)しかし、改行を含むファイル名がある場合、いくらかそれに値する... ;-)


「次に、コマンドを適用します(なぜですか?)」-> statは、ファイル名を使用してbashループを実行する方法を試しているため、任意のコマンドとして機能します。それはgpg、gzipまたは他の何でもかまいません。
user258532

@ user258532コマンドに関係なく、常にを使用しますfor f in *; do command "$f"; done。決して解析しないでくださいls、決してfor ループで決して実行しないでくださいecho
terdon 2015年

echo:コマンドを複数行で書くのが好きなので... :)
user258532

2
@ user258532えっ?なぜエコーが必要なのですか?Enterキーを押して改行します。開いている引用符で行を終了またはの1にした場合do|&&など、あなたが新しい行に続けることができます。それか、ヒアドキュメントを使用してください。使用する理由echoもなく、問題が発生する可能性もあります。
terdon 2015年

「Enterキーを押して改行を続けるだけです。」痛い。:-Dこれで、私のIQは正式に0を下回っています。しかし、私は実際にR(統計スイートとスクリプト言語)でお金を稼いでいます。
user258532

6

Enter余談です:を使用して複数のプロセスをフォークする代わりに、スペースとその後にバックスラッシュを追加し、毎回ヒットすることで、長く複雑なコマンドを複数の行に分割できますecho [...] | bash。また、ファイル名にスペースが含まれている場合に改行されないように$file、二重引用符で囲む必要statがあります。

for file in $(ls); \
do \
stat "$file"; \
done

問題は、$(ls)スペースを含むファイル名のリストに展開されることであり、同じことがでも発生し"$(ls)"ます。

この問題を解決しても、このメソッドは、バックスラッシュを含むファイル名と、改行を含むファイル名(terdonによって指摘されたとおり)で壊れます。

両方の問題の解決策はfindwhileループの実行にの出力をパイプしread -rて、各反復での出力のread -r1行をに格納findすること$fileです。

find . -maxdepth 1 -type f | while read -r file; do \
    stat "$file"; \
done

1
と隠しファイル?:)
AB

5
それでも、改行を含むファイル名では失敗します。解析しないでくださいls。ずっと。
terdon 2015年

4
@ user258532いいえ、ありません。真剣に、解析しないでくださいls。より良い、より堅牢な方法があります。これも読みたいかもしれません:なぜ `ls`を解析しないのですか?詳細については。
terdon 2015年

1
ここでの問題はls、そうではありませんfor- キーワードの後に指定forされた(IFSで区切られた)単語を反復しますin `
glenn jackman

1
@glennjackmanはい、それはforとの組み合わせですlsfor f in *たとえば、大丈夫でしょう。
terdon

3

古き良きを使用し、find隠しファイル、改行、スペースで動作します。

find . -print0 | xargs -I {} -0 stat {}

または代わりに他の stat

find . -print0 | xargs -I {} -0 file {}
find . -print0 | xargs -I {} -0 cat {}

1

Rの人として、私はすでにRで回避策を見つけました:

filenames <- dir(); # reads file names into an array.
                    # It works also recursively
                    # with dir(recursive=TRUE)
for (i in 1:length(filenames)) {
system(     # calls a system function
 paste(     # join stat and the file name
  "stat",
  filenames[i]
 )
)
}

私は知っています、それは怒っています。私はの出力は希望lsの解析に容易になるだろう... dirが()引用符で囲まれた文字値を返すためRは、スペースを扱うことができます。引用符の間にあるものはすべて、スペースを含む有効なファイル名です。


3
気にしないでください(ただし、努力して+1してください!)。ただ、使用しfor f in *、入力して、新しい行に続けるヒット:do、もう一度、Enterキーを押しstat "$f"、もう一度入力し、done入力します。これは4行でうまく分割されたコマンドであり、どのようなファイル名でも中断しません。
terdon 2015年

1

forループで空白の問題の他のインスタンスに遭遇したので、次の(imoより堅牢な)コマンドが通常使用します。また、パイプにうまくフィットします。

$ ls | while read line; do stat "$line"; done;

これを組み合わせるgrepか、find代わりに使用することができます:

$ find ./ -maxdepth 2 | grep '^\./[/a-z]+$' | while read line; do stat "$line"; done;

最初の回答は、バックスラッシュ、または先頭または末尾のスペースを含むファイル名では失敗します。-Eオプションをgrepに追加しない限り、2番目の回答は完全に失敗します。オプションを追加しない+と、正規表現で認識されません。それでも、grep スペースが含まれているファイル名を削除するので、この質問のスイングとミスです。また、質問の例のように、数字(数字)と句読点(括弧など)を含むファイル名も削除します。また、改行を含むファイル名や-(ダッシュ)で始まるファイル名についても触れていません。
スコット

-1

この答えは、解析の問題を解決しls、バックスペースと改行を処理します

これを試してみてください。内部フィールドセパレータIFSを使用して問題を解決します。

IFS="\n" for f in $(ls); do   stat "$f"; done

しかし、あなたは簡単にそれを使ってls出力を解析する必要なしにそれを解決することができます

for f in *; do   stat "$f"; done

1
隠しファイルでは機能しません。
AB

2
OPは隠しファイルを要求しませんでした
Maythux

1
IFSここで変更する必要がある理由がわかりません。変数の引用は、単語の分割を防ぐのに十分なはずです。
steeldriver

解析用ls
Maythux、2015年

反対票は何ですか!!!
Maythux

-1

代わりに、スペースをアンダースコアなどの他の文字に置き換えてファイルの名前を変更できます。これにより、この問題を回避できます。

これを行うには、コマンドを簡単に実行します。

for file in * ; do mv "$f" "${f// /_}" ; done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.