すべてのテキストファイルが改行文字で終わることを保証するスクリプトを作成しようとしています。
特定のフォルダでこのコマンドを実行すると、次のようになります。
find . -exec ed -s {} <<< w \;
次の結果が表示されます。
Newline appended
Newline appended
Newline appended
Newline appended
Newline appended
Newline appended
Newline appended
Newline appended
Newline appended
Newline appended
Newline appended
いいですね。しかし、どのファイルに改行文字が追加されますか? Git 履歴に変更は表示されません。追跡されていないファイルも同じですか?
また、意図的にテキストファイルの末尾から改行文字を削除してed
再追加しませんでした。
答え1
<<<
入力リダイレクト(ここでは文字列)がfind
代わりに追加されたため、コマンドは少し間違っていますed
。
コマンドを少し拡張します。
find . -type f -exec sh -c '
for pathname do
echo w | ed -s "$pathname"
done' sh {} +
これは現在のディレクトリまたはその下の通常のファイルにのみ影響し、使用しようとしませんed
。バイナリファイルも通常のファイルであるため、テキストファイルを含むディレクトリでのみ実行されていると仮定する必要があります。コンパイルされた実行ファイル、イメージファイルなどを破損しないように)
通常のファイル配置では、短いインラインシェルスクリプトが呼び出されます。スクリプトは与えられたパス名を繰り返してからfind
各パスを開き、すぐにed
ファイルを保存します。これにより、改行文字で終わっていないファイルに改行文字が追加されます。
どのファイルが実際に変更されたかについてのヒントを得るには、を呼び出す前にパス名を印刷しますed
。これは出力されますみんなパス名が見つかりましたが、リストの一部のパスの後に「新しい行を追加」というメッセージが散在しています。
find . -type f -exec sh -c '
for pathname do
printf "%s\n" "$pathname"
echo w | ed -s "$pathname"
done' sh {} +
実際に変更されたファイルを検索するには、一時ファイルに書き込んで元のファイルと比較し、違いがある場合は元のファイルを一時ファイルに置き換えます。
find . -type f -exec sh -c '
tmpfile=$(mktemp); trap "rm -f \"$tmpfile\"" EXIT
for pathname do
printf "w %s\n" "$tmpfile" | ed -s "$pathname" 2>/dev/null
if ! cmp -s "$tmpfile" "$pathname"; then
printf "Fixed %s\n" "$pathname"
mv "$tmpfile" "$pathname"
fi
done' sh {} +
これのもう1つの利点は、実際には変更されたファイル以外のファイルのタイムスタンプを更新しないことです。
これにより、「改行の追加」メッセージも抑制さed
れ、ファイルが実際に変更されたときにカスタムメッセージが出力されます。
また見なさい: