web-dev-qa-db-ja.com

rm $(ls)を使用してファイルを削除することの欠点はありますか?

rm $(ls)を使用してファイルを削除する(またはrm -r $(ls)を使用してディレクトリを削除する)のは安全かどうか疑問に思っていましたか?すべてのWebサイトで、このコマンドは他のコマンドよりもはるかに簡単に見えても、人々は他の方法でこれを行うためです。

13
posixKing

これは何をするつもりですか?

  • lsは、現在のディレクトリ内のファイルをリストします
  • $(ls)は、lsの出力をrmの引数として置き換えます
  • 基本的にrm $(ls)は、現在のディレクトリ内のすべてのファイルを削除することを目的としています

この写真の何が問題になっていますか?

lsは、ファイル名の特殊文字を適切に処理できません。 Unixユーザーは一般的に 異なるアプローチの使用を推奨 。また、それを ファイル名のカウントに関する関連質問 で示しました。例えば:

$ touch file$'\n'name                                                                                                    
$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ 

また、デニスの回答で適切に言及されているように、先頭にダッシュが付いたファイル名は、置換後にrmへの引数として解釈される可能性があり、ファイル名を削除する目的に反します。

動作するもの

現在のディレクトリのファイルを削除したい。したがって、グロブrm *を使用します。

$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ rm *
$ ls
$ 

findコマンドを使用できます。このツールは、現在のディレクトリ以外にも頻繁に推奨されます。ディレクトリツリー全体を再帰的に走査し、-exec . . .{} \;を介してファイルを操作できます。

$ touch "file name"                                
$ find . -maxdepth 1 -mindepth 1                                                                                         
./file name
$ find . -maxdepth 1 -mindepth 1 -exec rm {} \;                                                                          
$ ls
$ 

Pythonはファイル名に特殊文字を使用する問題がないため、これも使用できます(これはファイル専用であり、操作する場合はos.rmdir()およびos.path.isdir()を使用する必要があります。ディレクトリ上):

python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

実際、上記のコマンドは、簡潔にするために~/.bashrcで関数またはエイリアスに変換できます。例えば、

rm_stuff()
{
    # Clears all files in the current working directory
    python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

}

Perlバージョンは

Perl -e 'use Cwd;my $d=cwd();opendir(DIR,$d); while ( my $f = readdir(DIR)){ unlink $f;}; closedir(DIR)'
7

いいえ、安全ではありません。また、一般的に使用される代替rm *はそれほど安全ではありません。

rm $(ls)にはmany問題があります。他の人がすでに回答で説明しているように、lsの出力は 内部フィールド区切り記号 にある文字で分割されます。

ベストケースのシナリオ、それは単に機能しません。最悪の場合のシナリオでは、ファイルのみ(ディレクトリは除く)を削除するか、または-iの一部のファイルを選択的に削除しようとしましたが、現在のディレクトリにc -rfという名前のファイルがあります。しばらく様子を見てみましょう。

$ mkdir a
$ touch b
$ touch 'c -rf'
$ rm -i $(ls)
$ ls
c -rf

コマンドrm -i $(ls)はファイルのみを削除し、各ファイルを削除する前に確認することになっていますが、最終的に実行されたコマンドは読み取り

rm -i a b c -rf

まったく別のことをしました。

rm *はわずかに優れているだけです。以前のディレクトリ構造では、ここで意図したとおりに動作しますが、-rfというファイルがある場合は、まだ運がありません。

$ mkdir a
$ touch b
$ touch ./-rf
$ rm -i *
$ ls
-rf

いくつかのより良い代替手段があります。最も簡単なのは、rmとグロビングのみです。

  • コマンド

    rm -- *
    

    --は、それ以降はすべてオプションとして解釈されるべきではないことを通知します。

    これは20年以上にわたってPOSIXユーティリティの構文ガイドラインの一部でした。それは広まっていますが、至る所に存在することを期待すべきではありません。

  • コマンド

    rm ./*
    

    グロブの展開方法を変えるため、呼び出されたユーティリティからのサポートは必要ありません。

    上記の例では、先頭にechoを追加することで最終的に実行されるコマンドを確認できます。

    $ echo rm ./*
    rm ./a ./b ./-rf
    

    先頭の./は、rmがオプションのようなファイル名を誤って処理するのを防ぎます。

27
Dennis