ファイル名に空白とか入っていると、ファイル名のリストが入った引数の変数をforで回したときに、空白でファイル名が分割されちゃって期待した動きにならないよね。
ファイル名に空白てかスペースがあっただけで処理で躓くって、シェルスクリプトってショボ過ぎじゃん。シェル力はもったいない
IFS環境変数を使え
対策はフィールドセパレータ環境変数を設定するだけの事で、具体的にはIFSに改行をセットすれば良い。
IFSに改行(\n)をセットすることで、入力の一行を一ファイル名として容易に処理することが可能。
なお、IFS(IFS変数)とはInternal Field Separatorであり、安心の標準機能。
#!/bin/bash
IFS="
"
for FILE in `find . -type f -print`
do
md5sum "$FILE"
done > hoge.txt
(上記の場合重要なのは、IFS変数をセットしている行の記述で”の前後のスペースとかタブに気をつけるという事。いうまでもないことだけど、改行だけをセットするように )
または・・「シェルスクリプトちょっとデキル」な人は次な風で
#!/bin/bash
IFS=$'\n'
for FILE in `find . -type f -print`
do
md5sum "$FILE"
done > hoge.txt
互換性の問題なのか知らんけどIFSやFS変数のデフォルト設定値が古く、今時の空白を含んだファイル名に対処できないというのはちと問題な気がするなあ。せっかくのシェル力が勿体ないよ。
IFS=$’\n’を忘れないための補足
IFS=$’\n’の$’だが、以降の文字列がエスケープシーケンス付きであると示す文法。 エスケープシーケンスの例としては、NewLineの場合\n、タブ文字ならば\tとなる
それとこの$’\n’を使った後者だが、前者の場合と動きが違うことがあった。後者でなんか変なことがあったり、処理できない場合には前者を使ってみてね。
ワンライナーでやりたい&[ぐち]forコマンドがIFS環境変数を一時使用できれば、こんな面倒なことにならずに済むのに
そもそも for FILE in * の空白処理が期待にマッチしないわけで、環境変数の一時使用の
IFS=$'\n' for FILE in `find . -type f`...
っぽいことができれば何の苦労もないのに。グローバルなドメインのIFSをイジるとか嫌過ぎる。
(IFS=$'\n';for FILE in `find . -type f`;do md5sum $FILE;done > hoge.txt)
上はIFS環境変数を汚さず、ワンライナーでやる場合
IFSとか コマンド置換がイヤンな場合
コマンド置換は大量にファイルを処理したいとか入力がかなりある時はイヤンだよな。find -execやxargsに切り替えようとして悩んだら、 こう変化させるのも手かと思う
#! /bin/sh
find . -type f -print | while read FILE
do
md5sum "$FILE"
done > hoge.txt
- ただしパイプの先は別のプロセスであることを絶対に忘れてはいけない。絶対にだ。
- とはいってもハマるだろうけどね。まあやってみてくれ
- find -execって遅いのな。当たり前というか意外というか
蛇足(上のmd5sumをPowershellで) 自分用
ほぼというか全く関係がない汗
get-childitem . | foreach-object { get-filehash -algorithm md5 $_ }
だがこれ、結果のPathがクソ長すぎて役に立たないのはお約束。もうひと手間必要。MSはクソってことをわすれてはいけな い絶対にだ。