web-dev-qa-db-ja.com

lsは、rmが削除するファイルを常にリストしますか?

確実に知っておくべきこと:ls <something>の場合、rm <something>lsが表示したものとまったく同じファイルを削除しますか? rmが表示されなかったlsのファイルを削除できる状況はありますか? (これは18.04 bashにあります)

編集:答えたすべての人に感謝します。完全な答えはすべての答えの組み合わせであると思うので、私は最も回答の多い答えを「答え」として受け入れました。

途中で学んだ予期しないこと:

  • lsは、引数の処理で考えるほど簡単ではありません
  • Ubuntuの単純な未調整インストールでは、.bashrcエイリアスls
  • コマンドの引数のように見える可能性があるため、ダッシュで始まるファイルに名前を付けないでください。-rという名前を付けると、それが要求されます。
33
B.Tanner

さて、lsrmは両方とも、渡される引数に作用します。

これらの引数は単純なファイルにすることができるため、ls file.extrm file.extは同じファイルで動作し、結果は明確です(ファイルをリストする/ファイルを削除する)。

代わりに引数がディレクトリの場合、ls directoryはディレクトリの content をリストしますが、rm directoryはそのままでは機能しません(つまり、rmはフラグなしでディレクトリを削除することはできませんが、rm -r directoryを実行すると、[ all files under directoryおよびディレクトリ自体)を再帰的に削除します。

ただし、コマンドライン引数は Shell Expansion の対象になる可能性があるため、同じ引数が両方に渡されることは常に保証されませんコマンドにワイルドカード、変数、他のコマンドからの出力などが含まれている場合.

極端な例として、ls $(Rand).txtrm $(Rand).txtを考えてください。引数は「同じ」ですが、結果はまったく異なります。

40
Mr Shunz

ls foo*.txt vs. rm foo*.txtのようなものを考えているなら、はい、同じファイルを表示して削除します。シェルはグロブを展開し、問題のコマンドに渡します。コマンドはリストされたファイルで機能します。それらをリストするもの、削除するもの。

明らかな違いは、これらのファイルのいずれかがディレクトリである場合、lsはその内容をリストしますが、rmは削除に失敗することです。 rmlsで表示されたものよりもlessを削除するため、通常は問題になりません。

ここでの大きな問題はダッシュで始まるファイル名を含むディレクトリでls *またはrm *を実行しています。これらは、自分で作成したかのように2つのプログラムのコマンドラインに展開され、ls-rを「逆ソート順」を意味し、rm-rは再帰的な削除を意味します。少なくとも2レベルの深さのサブディレクトリがある場合、違いは重要です。 (ls *は最初のレベルのディレクトリの内容を表示しますが、rm -r *は最初のサブレベル以降もすべて表示します。)

これを回避するには、現在のディレクトリを示す./を先頭に付けて寛容なglobを記述し、および/またはglobの前にオプション処理の終了を示す--を配置します(つまりrm ./*またはrm -- *)。

*.txtのようなglobでは、ドットは無効なオプション文字であるため実際には問題ではなく、エラーが発生します(誰かがユーティリティを展開してその意味を発明するまで)が、それでも安全です./とにかく。


もちろん、シェルのグロビングオプションを変更した場合、またはコマンド間でファイルを作成/移動/削除した場合、2つのコマンドで異なる結果が得られる可能性がありますが、これらのケースのいずれかを意味しているとは思いません。 (新規/移動されたファイルを扱うことは、安全に行うには非常に面倒です。)

20
ilkkachu

シェルの動作はさておき、rmlsが自分自身で対処できるものだけに注目しましょう。 lsが削除できないrmが表示される場合の少なくとも1つのケースには、ディレクトリのアクセス許可が含まれ、その他の特別なディレクトリ.および..が含まれます。

フォルダーのアクセス許可

rmはディレクトリに対する操作です。ファイルを削除すると、ディレクトリの内容が変更されるためです(つまり、d ディレクトリはファイル名のリストに過ぎず、 iノード )。つまり、ディレクトリに対する書き込み権限が必要です。 ファイルの所有者であっても 、ディレクトリのアクセス許可がない場合、ファイルを削除できません。 reverseもtruermは、ディレクトリ所有者であれば、他のユーザーが所有している可能性のあるファイルを削除できます。

そのため、ディレクトリに対する読み取りおよび実行権限があります。これにより、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 '.'
17

ls *およびrm *は、globの拡張に責任を負いません。これは、コマンドに渡す前にシェルによって行われます。

これは、拡張ファイルリストでanyコマンドを使用できることを意味します。したがって、できる限り使用しないものを使用します。

したがって、これを行うためのより良い方法(または少なくとも、別の方法)は、仲介者をスキップすることです。

echo *は、rmコマンドに渡されるものを正確に表示します。

9
Shadow

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)

それがお役に立てば幸いです。

4
DevHugo

どうですか:

$ mkdir what
$ cd what
$ mkdir -p huh/uhm ./-r
$ ls *
uhm
$ rm *
$ ls
-r
$ ls -R
.:
-r

./-r:

基本的に、-で始まるもの(または-で始まるものを手動で入力したものの、少し不正行為に見えるワイルドカード)は、lsrmによって解釈が異なる場合があります。

4
user868053

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 ...
4
alexis

すでに多くの良い答えがありますが、もう少し深い洞察を加えたいと思います。

次の質問を自問してください: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 *を実行します。その出力から学ぶ!

3
rexkogitans

グロブは両方の時間で同じように展開します。ifディレクトリの内容はこれらの2つの異なる時間で同じです。


削除するものを本当に確認したい場合は、rm -i *.txtを使用します。削除(試行)する前に、ファイルごとに個別にプロンプ​​トが表示されます。

これにより、競合状態に対して安全であることが保証されます。
ls *.txt /新しいファイルが作成されました/ rm *.txt
削除を実行しているのと同じプログラムからすべてのファイルの入力を求められるためです。


これは通常の使用には扱いにくいため、rmrm -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 -Iman page )で、これは4つ以上のアイテムを削除する場合にプロンプ​​トを出します。 (ただし、リストは表示されず、合計のみが表示されます。)私はデスクトップでalias rm='rm -I'を使用します。

これは、あまりにも多く一致するハーフタイプのパターンを使用した、脂肪の多い戻りに対する素敵な保護手段です。しかし、最初にlsを使用することは、一般に、所有するディレクトリまたはシングルユーザーシステムで、非同期的に新しいファイルを作成できるバックグラウンドプロセスがない場合に適しています。太りすぎを防ぐため、rm -rf /foo/bar/bazを左から右に入力しないでください。 rm -rf /は特殊なケースですが、rm -rf /usrはそうではありません! -rf部分を省略するか、lsで開始し、パスを入力した後にのみrm -rf部分を追加します。

1
Peter Cordes