web-dev-qa-db-ja.com

通常のファイルのみを `sed -i`に渡す

私はGNU sed 4.2.2を使用していますが、検索後にsedがいくつかの状況で奇妙に動作する理由を見つけることができません:

次のディレクトリがあります:

foofile.txt
barfile.txt
bazfile.txt
config/

事例1

sed -i 's/foo/bar/g' *.txt

これは期待どおりに機能します。これは、3つの通常ファイル内のすべての「foo」を「bar」に置き換えます。

事例2

sed -i 's/foo/bar/g' *
sed: couldn't edit config: not a regular file

barfile.txtbazfile.txtでは「foo」を「bar」に置き換えますが、foofile.txtでは置き換えません。私はそれが*からアルファベット順に展開されたファイルのリストを通過し、config/にヒットするとエラーになって終了すると想定しています。 sedでエラーを無視してファイルの処理を続行する方法はありますか?

事例3

for file in $(find . -maxdepth 1 -type f); do sed -i 's/foo/bar/g' <"$file"; done
sed: no input files
sed: no input files
sed: no input files

誰かがsedがなぜこれを行うのか説明してもらえますか?入力ファイルが与えられたときに入力ファイルがないと表示されるのはなぜですか?

以下を使用できることはわかっていますが、sedがこのように動作する理由を尋ねています。この1つの使用例を解決する方法ではありません。

find . -maxdepth 1 -type f -exec sed -i 's/foo/bar/g' {} \;
3
Linoob

これは正常な動作です。どちらの場合でも、sederror code 4ごとにinfo sed...で終了します。

4
     An I/O error, or a serious processing error during runtime,
     GNU 'sed' aborted immediately.

どちらの場合も、メッセージは自明です。何が不明確なのかはわかりませんが、記録についてです。ディレクトリを編集できないために最初にエラーが発生し、stdinを直接編集できないためにエラーが発生した場合は、ファイルが必要です(つまり、リダイレクトを削除します) $fileより前)
findを使用してこれを行う適切な方法は、お気付きのとおり、-exec ...を使用することです
グロブを使用する場合、sedを実行する前に、ループを使用して、入力が通常のファイルであるかどうかをテストする必要があります。または、zshユーザーの場合は、次のようにすることができます。

sed -i 's/foo/bar/g' *(.)
4
don_crissti
  • ケース2:

    findでそのディレクトリを避けてください:

    sed -i 's/foo/bar/g' `find . -maxdepth 1 -type f`
    
  • ケース3:

    問題は<"$file"ループ内では、ファイルをストリームに変換するため、sedはファイル名を見ることはありません。削除してください<

    for file in $(find . -maxdepth 1 -type f); do sed -i 's/foo/bar/g' "$file"; done
    
1
agc