確実に知っておくべきこと:ls <something>
の場合、rm <something>
はls
が表示したものとまったく同じファイルを削除しますか? rm
が表示されなかったls
のファイルを削除できる状況はありますか? (これは18.04 bashにあります)
編集:答えたすべての人に感謝します。完全な答えはすべての答えの組み合わせであると思うので、私は最も回答の多い答えを「答え」として受け入れました。
途中で学んだ予期しないこと:
ls
は、引数の処理で考えるほど簡単ではありませんls
さて、ls
とrm
は両方とも、渡される引数に作用します。
これらの引数は単純なファイルにすることができるため、ls file.ext
とrm file.ext
は同じファイルで動作し、結果は明確です(ファイルをリストする/ファイルを削除する)。
代わりに引数がディレクトリの場合、ls directory
はディレクトリの content をリストしますが、rm directory
はそのままでは機能しません(つまり、rm
はフラグなしでディレクトリを削除することはできませんが、rm -r directory
を実行すると、[ all files under directory
およびディレクトリ自体)を再帰的に削除します。
ただし、コマンドライン引数は Shell Expansion の対象になる可能性があるため、同じ引数が両方に渡されることは常に保証されませんコマンドにワイルドカード、変数、他のコマンドからの出力などが含まれている場合.
極端な例として、ls $(Rand).txt
とrm $(Rand).txt
を考えてください。引数は「同じ」ですが、結果はまったく異なります。
ls foo*.txt
vs. rm foo*.txt
のようなものを考えているなら、はい、同じファイルを表示して削除します。シェルはグロブを展開し、問題のコマンドに渡します。コマンドはリストされたファイルで機能します。それらをリストするもの、削除するもの。
明らかな違いは、これらのファイルのいずれかがディレクトリである場合、ls
はその内容をリストしますが、rm
は削除に失敗することです。 rm
はls
で表示されたものよりもlessを削除するため、通常は問題になりません。
ここでの大きな問題はダッシュで始まるファイル名を含むディレクトリでls *
またはrm *
を実行しています。これらは、自分で作成したかのように2つのプログラムのコマンドラインに展開され、ls
は-r
を「逆ソート順」を意味し、rm
は-r
は再帰的な削除を意味します。少なくとも2レベルの深さのサブディレクトリがある場合、違いは重要です。 (ls *
は最初のレベルのディレクトリの内容を表示しますが、rm -r *
は最初のサブレベル以降もすべて表示します。)
これを回避するには、現在のディレクトリを示す./
を先頭に付けて寛容なglobを記述し、および/またはglobの前にオプション処理の終了を示す--
を配置します(つまりrm ./*
またはrm -- *
)。
*.txt
のようなglobでは、ドットは無効なオプション文字であるため実際には問題ではなく、エラーが発生します(誰かがユーティリティを展開してその意味を発明するまで)が、それでも安全です./
とにかく。
もちろん、シェルのグロビングオプションを変更した場合、またはコマンド間でファイルを作成/移動/削除した場合、2つのコマンドで異なる結果が得られる可能性がありますが、これらのケースのいずれかを意味しているとは思いません。 (新規/移動されたファイルを扱うことは、安全に行うには非常に面倒です。)
シェルの動作はさておき、rm
とls
が自分自身で対処できるものだけに注目しましょう。 ls
が削除できないrm
が表示される場合の少なくとも1つのケースには、ディレクトリのアクセス許可が含まれ、その他の特別なディレクトリ.
および..
が含まれます。
rm
はディレクトリに対する操作です。ファイルを削除すると、ディレクトリの内容が変更されるためです(つまり、d ディレクトリはファイル名のリストに過ぎず、 iノード )。つまり、ディレクトリに対する書き込み権限が必要です。 ファイルの所有者であっても 、ディレクトリのアクセス許可がない場合、ファイルを削除できません。 reverseもtrue :rm
は、ディレクトリ所有者であれば、他のユーザーが所有している可能性のあるファイルを削除できます。
そのため、ディレクトリに対する読み取りおよび実行権限があります。これにより、ls /bin/echo
など、ディレクトリ内を移動してコンテンツを表示できますが、rm /bin/echo
はできません。 /bin
の所有者、またはSudo
で特権を昇格します。
そして、あなたはこのようなケースをどこでも見るでしょう。そのような場合の例を次に示します。 https://superuser.com/a/331124/418028
別の特殊なケースは、.
および..
ディレクトリです。 ls .
またはls ..
を実行すると、コンテンツは喜んで表示されますが、rm
'ingは許可されません。
$ rm -rf .
rm: refusing to remove '.' or '..' directory: skipping '.'
ls *
およびrm *
は、globの拡張に責任を負いません。これは、コマンドに渡す前にシェルによって行われます。
これは、拡張ファイルリストでanyコマンドを使用できることを意味します。したがって、できる限り使用しないものを使用します。
したがって、これを行うためのより良い方法(または少なくとも、別の方法)は、仲介者をスキップすることです。
echo *
は、rm
コマンドに渡されるものを正確に表示します。
ls -a
の代わりにls
のみを行う場合、はいrm
は、-a
なしでls
を使用して見たことがない隠しファイルを削除できます。
例:
による :
dir_test
├── .test
└── test2
ls dir_test
:test2のみを表示します
ls -A dir_test
:test2 + .testを表示します
rm -r dir_test
:すべてを削除します(.test + test2)
それがお役に立てば幸いです。
どうですか:
$ mkdir what
$ cd what
$ mkdir -p huh/uhm ./-r
$ ls *
uhm
$ rm *
$ ls
-r
$ ls -R
.:
-r
./-r:
基本的に、-
で始まるもの(または-
で始まるものを手動で入力したものの、少し不正行為に見えるワイルドカード)は、ls
とrm
によって解釈が異なる場合があります。
arels
が示すものがrm
が除去するものではないエッジケース。かなり極端ですが、幸いなことに、渡す引数がディレクトリへのシンボリックリンクである場合:ls
はシンボリックリンクディレクトリ内のすべてのファイルを表示し、rm
はシンボリックリンクを削除します。元のディレクトリとその内容はそのままです:
% ln -s $HOME some_link
% ls some_link # Will display directory contents
bin lib Desktop ...
% rm some_link
% ls $HOME
bin lib Desktop ...
すでに多くの良い答えがありますが、もう少し深い洞察を加えたいと思います。
次の質問を自問してください:ls
に渡されるパラメーターの数
ls *
...? *
を展開できるファイルがある場合、ls
コマンドは*
をパラメーターとして取得しないことに注意してください。代わりに、シェルはコマンドを呼び出す前に最初にグロビングを実行するため、ls
コマンドは実際にグロビングに一致するファイルと同じ数のパラメーターを取得します。グロビングを抑制するには、パラメーターを引用します。
これはすべてのコマンドに当てはまります:echo *
vs echo '*'
。
スクリプトがあり、それをcountparams.sh
と呼び、効果をテストします。渡されたパラメーターの数を示し、それらをリストします。
#!/bin/bash
echo "This script was given $# parameters."
arr=( "$@" )
for ((i=0;i<$#;i++)); do
echo "Parameter $((i+1)): ${arr[$i]}"
done
実行可能にして./countparams.sh *
を実行します。その出力から学ぶ!
グロブは両方の時間で同じように展開します。ifディレクトリの内容はこれらの2つの異なる時間で同じです。
削除するものを本当に確認したい場合は、rm -i *.txt
を使用します。削除(試行)する前に、ファイルごとに個別にプロンプトが表示されます。
これにより、競合状態に対して安全であることが保証されます。ls *.txt
/新しいファイルが作成されました/ rm *.txt
削除を実行しているのと同じプログラムからすべてのファイルの入力を求められるためです。
これは通常の使用には扱いにくいため、rm
をrm -i
にエイリアスすると、\rm
またはrm -f
をかなり頻繁に使用することになります。しかし、少なくとも競合状態の解決策があることに言及する価値があります。 (非GNUシステムにも移植可能です: POSIX rm(1)
は-i
オプションを指定します 。
別のオプションは、bash配列です:to_remove=(*.txt)
、ユーザーに確認するように要求します(おそらくls -ld -- "${to_remove[@]}"
を実行した後)、次にrm -- "${to_remove[@]}"
。したがって、glob展開は1回だけ実行され、リストはrm
に逐語的に渡されます。
別の実用的なオプションはGNU rm -I
( man page )で、これは4つ以上のアイテムを削除する場合にプロンプトを出します。 (ただし、リストは表示されず、合計のみが表示されます。)私はデスクトップでalias rm='rm -I'
を使用します。
これは、あまりにも多く一致するハーフタイプのパターンを使用した、脂肪の多い戻りに対する素敵な保護手段です。しかし、最初にls
を使用することは、一般に、所有するディレクトリまたはシングルユーザーシステムで、非同期的に新しいファイルを作成できるバックグラウンドプロセスがない場合に適しています。太りすぎを防ぐため、rm -rf /foo/bar/baz
を左から右に入力しないでください。 rm -rf /
は特殊なケースですが、rm -rf /usr
はそうではありません! -rf
部分を省略するか、ls
で開始し、パスを入力した後にのみrm -rf
部分を追加します。