防止用户在rm和通配符之间输入意外空格


29

意向:

rm -rf string*

问题:

rm -rf string *

第一种情况是rm的合法和普遍使用,第二种情况下小的错字可能会引起很多问题。有没有一种简单的方法可以巧妙地防止意外的尾随或前导通配符?


8
对于最近使用且配置良好的shell(zshbash),我宁愿养成在按回车键之前先按Tab键(触发自动完成)的习惯
Basile Starynkevitch 2015年

2
touch -- -i将创建一个文件-i,当您rm在参数中-i包含通配符时,该文件将作为参数传递给该文件。
恢复莫妮卡-M.Schröder'15

@MartinSchröder:如果碰巧在文件所在的目录中。
暂停,直到另行通知。

@MartinSchröder只有在键入时才有效rm *。如果键入rm name *,它将扩展为rm name -i other names-i将不会作为选项处理,因为它不在文件名之前。
Barmar

1
通常,用户只执行一次。
tedder42

Answers:


37

DEBUG可以编写一个陷阱来取消看似可疑的命令。可以将以下或类似的代码添加到您的~/.bashrc

shopt -s extdebug
checkcommand() {
  if [[ $BASH_COMMAND = 'rm -r'*' *' ]]; then
    echo "Suppressing rm -r command ending in a wildcard" >&2
    return 1
  fi
  # check for other commands here, if you like
  return 0
}
trap checkcommand DEBUG

调整逻辑以品尝。

(我实际上并不期望这种方法有用-太多破坏性地弄乱命令以使其一步一步进行测试的方法-但这确实为问题提供了答案)。


47

无法完全防弹系统。并添加“您确定吗?” 对事情的提示既适得其反,又会导致“我确定。” 膝关节反应。

我几年前从一本书中摘取的一个诀窍是,首先要做的是ls -R blah*rm -fr blah* 并且仅当ls出现的清单达到我想要的目标时才这样做 。

首先执行ls命令非常容易,然后删除ls -R并替换为rm -fr

最后一个问题是:“如果信息对您有价值,那么备份在哪里?”


4
您可以使用而不是向上箭头,也可以将其^ls -R^rm -rf^设置为别名
exussum,2015年

FWIW,这是ls -R我一直以来一直在做的事情,但是这是本能的本能,当我通过回答形成时,这使我的意识丧失了。所以+1。
JakeGould 2015年

这还具有以下优点:如果您按Enter键或碰触鼠标并用换行符粘贴,则不会造成伤害。为了提高安全性,有时我会以效率较低的顺序输入内容,例如cat > .log,然后回去粘贴或粘贴文件名.log。所以我永远都不会> valuablefile在cmdline上。
彼得·科德斯

我使用rm别名为rm -i,因此通常只编写rm命令,然后\ 在行的开头放置a 。(\rm避免使用rm的别名扩展,因为部分单词被引用了)。如果我需要一个-r-f,是的,我有时会以ls而不是开头rm,或者只是省略-rf一部分。(编辑,您如何获得反斜杠代码格式?bquote bslash bslash bquote失败。–
Peter Cordes

8

您可以训练自己rmrf代替使用rm -rf吗?

如果是这样,此bash函数将使您有机会在确认命令之前查看实际发生的情况:

rmrf() { echo rm -rf "$@"; read -p "Proceed (y/N)? "; [ "${REPLY,,}" = y ] && rm -rf "$@"; }

要使此功能永久生效,请将此行添加到~/.bashrc您使用的每台计算机上的文件中。

与通用rm别名比较

定义别名是很常见的:

alias rm='rm -i'

这有两个限制:

  1. 如果您依赖于该别名,那么当您在没有该别名的计算机上或环境中时,您将感到震惊。相反,尝试rmrf在没有该功能的机器上运行将返回无害的结果command not found

  2. 在您的情况下,此别名无济于事,因为-f您在命令行上提供的-i选项将覆盖别名中的选项。


4
不错的主意。但这取决于此功能在该用户使用的任何系统上是否已安装并可用。因此,假设他们登录到远程服务器进行某些工作并运行错误的rm -rf命令,会发生什么?创建这样的伪函数最终只会使一个简单的解决方案复杂化:请更加小心并了解什么是权限。
JakeGould 2015年

4
@JakeGould 除非确实需要,否则不要使用rm -f
CVn 2015年

1
为什么不打扰rmrf,而不是仅仅创建一个外壳函数rm来检查参数-ror -rf,并在这种情况下制定特殊逻辑,否则直接调用command rm "$@"以调用真实rm命令?
查尔斯·达菲

3
您使用了另一个名称,因此当您的覆盖不存在时,您不会把自己开枪。我同意@MichaelKjörling,你并不需要-f,如果你没有-i-f例如,在删除只读文件之前,先离开会给您额外的警告。
彼得·科德斯

6

如果我遇到的情况是删除错误的文件非常重要,那么我要做的一件事情就是创建一个垃圾桶文件夹,例如mkdir trashcan,然后我有一个脚本rmTrashcan,该脚本包含一个rm -rf trashcan/*或多个rm -rf *或类似名称,请务必谨慎地编写并检查了几次。

这样,如果我犯了一个错误,那么错误就是mv命令,而不是rm命令。一旦执行了a ls并且对我要删除的内容完全有信心,a rmTrashcan实际上就可以安全地执行肮脏的工作。

对于不得不删除备份的情况,这也非常方便。我可以mv将整个月的备份保存到垃圾箱中,然后mv将我想保留的备份备份(每月的1号,每月的15号)备份,然后rmTranshcan其余的备份。很难单独执行类似的命令rm,并且通过这种方式使我ls的备份对我要保留的文件充满信心(而不仅仅是枚举要删除的文件)


4

我认为不用麻烦两个命令(lsrm),而是一种更简单的方法find

find . -maxdepth 1 -name "string*" -delete

如果您不小心键入"string *",它将删除名为string chars和的文件string letters(无论如何,这都是您想要的),但是它不会像*在shell中那样捕获每个文件。

此外,您可以不-delete选择查看要删除的文件,然后按向上箭头键并键入-delete比输入^ls -R^rm -rf或其他无用的内容更容易。


A find将对匹配的文件进行嵌套搜索,而不仅仅是在命令行上声明的显式参数。我认为这没有实现目标。我可能是错的。
killermist 2015年

3

有没有一种简单的方法可以巧妙地防止意外的尾随或前导通配符?

并不是的。在另一个答案中提出了建议,您可以创建一个自定义命令以在执行任务之前添加提示。但是此自定义命令的问题在于必须有意识地将其安装在您正在使用的系统上。而且即使安装了它,问题仍然在于您是否想通过击打y来完成任务。

这意味着,即使在文本/命令行级别,这也是所有用户界面问题。您希望有多少个安全网来保护您免受不必要的伤害?就像一把剪刀:如果您因疏忽大意而打算剪布或剪纸时打滑而割手,谁来过错?甚至是交通信号灯和停车标志:除了敏锐地意识到如果驾驶员从事此类危险行为会发生什么,实际上没有什么能阻止驾驶员开灯或无视交通标志。

就是说,最佳,现实的解决方案在于用户和组的系统权限。那是保护用户免受自身伤害的最好/唯一的真实安全网。

如果您正在一个只有一个人访问的系统上工作,那么您可能会想尽chmod 777一切办法,但是那并不是建立一个合理的系统的方式。相反,755对于所有目录和644所有不可执行的文件,权限应该类似于。可执行文件755至少应是,但即使744您只希望其他人读取但不运行文件,也可以。


2

尝试在rm不带-f标志的情况下编写初始命令,而是在不带标志的情况下编写-i,这样rm会提示您输入要删除的每个文件。对于小的递归删除,y一旦确定命令输入正确,就可以按住该键。对于大的删除,您可以中止该操作,并使用命令行历史记录将小心地更改-i-f


实际上,您必须按y[RETURN]每个文件,而GNU rm却无所不能。-i正确键入命令后,删除方法是可行的。然后,您仅在只读文件和其他内容上得到提示。
彼得·科德斯

1
只需使用rm -I,使其仅提示一次,并且仅提示潜在的危险删除(即删除许多文件。)
Nick Matteo

1
在建设性较差的论坛中,我的回答应该是“如果您的打字/校对太糟糕了,您就不会在通配符上使用'rm -rf'了”。我不知道-I开关...一定是在20年前安装的;“最后一次,我做了'人rm'。:)
内文·威廉姆斯

2

rm带有-i-I标志,以便在每次删除之前进行确认。过去,某些发行版默认情况下将其打开。这是一个可怕的主意。给用户太多的确认对话框以进行正常操作,他们将开始习惯性地进行确认。这只是将“小心”(总是带有红色标记)的要求转移到了一个新的,更烦人的对话框上。“是的。是的。是的。是的!是的!老天,该死的愚蠢的计算机只删除了文件。是的是的是的-抓拍我的意思是不!不!这是“是,但我不是”对话框问题。 该答案以直观的方式说明了为什么在错误的时间出现确认对话框。

您描述的那种错误是一种错误,即“执行某项操作而不是预期的操作”。用户通常会立即发现错误并确切知道如何解决。不幸的是,Unix没有给用户机会,rm会立即删除文件。每个其他操作系统都通过使用垃圾箱允许删除删除操作,至少有一小段时间来解决此问题。

Unix有各种各样的垃圾系统,这个答案充满了建议

问题是给rm别名还是不给rm别名。别名rm的优点...

  1. 您不会忘记使用rm选项。

别名rm的缺点...

  1. 您可能会依赖于没有它的系统。
  2. 磁盘快满时可能会引起问题。
  3. 需要基础架构来定期清空垃圾。
  4. 必须确保不干扰程序中rm的预期行为。
  5. 可能无法完全模拟rm。

如果您太过遵循第一个参数,则最终会使用vi(不是vim,vi),csh(不是tcsh,csh)和其他过时的实用程序,因为它们普遍可用。尽管如此,仍然存在过度定制环境的危险。我更喜欢随身携带公用程序,并使其尽可能简单。YMMV。

第二和第三是技术问题。可以通过巧妙的收割工作来解决这些问题,该工作可以检查垃圾箱的大小并定期清理东西,类似于tmpreaper。这可能是一项艰巨的任务,或更聪明的版本可以利用许多桌面Linux发行版上可用的各种文件系统事件基础结构。这并不简单,甚至更难有效地执行。找到一个现有系统比尝试创建自己的系统要好。

可以通过将新rm设置为shell别名来解决第四个问题alias rm='trash',这不会影响程序。

第五是我留给读者解决的问题。rm没有太多的开关。


我将rm别名为rm -i,但是我经常使用它\rm来获得无混淆的行为。我rm -i计划在任何时候都对其中一个参数说不。有时我会以命令开头ls,然后仅在完成后放入\ rm。因此,我无法无意中rm -rf /代替/.../file
Peter Cordes

rm -I,或者rm --interactive=once远不如烦人rm -i,并且仍然抓到任何危险(它仅在存在3个以上文件时提示,或者如果它是递归的,则仅提示一次,而不是每个文件。)
Nick Matteo

@Kundor是的,它不会改变方程式。这可能使用户更有可能忽略它。用户的目标是:删除内容。提示说:“您确定要删除刚才告诉我要删除的内容吗?” 用户仍然专注于删除内容的目的,而不是验证要删除的内容,因此他们不假思索地说“是”。-i可能会让用户有时间更改目标。有关相关问题的答案全部列出。
Schwern 2015年

@Schwern:但是rm -i如果没有关闭它,没有人可以忍受超过30秒。而rm -I仅在您可能被搞砸的时候提示;提示仅出现大的删除。当您尝试删除一些内容并给出提示时,您会大吃一惊,并意识到您不小心键入了“ foo *”。
Nick Matteo

@Kundor删除三个以上的文件并递归删除(该确认已被-rf我刚刚发现的习惯禁用)对于检测可能的损坏是不良的代理。想要删除子目录似乎不太可能。该消息无济于事,因为它只是确认用户所说的操作而没有在用户不希望验证时添加有用的信息。“ rm:递归删除1个参数?” “是的,删除目录,我只是告诉你这样做!……等等,那是哪个目录?CRAP !!!”
Schwern

2

我教大家关于!$最后一个命令技巧中的= last参数:

% ls job[XYZ].*
jobX.out1
jobX.out2
[rest of the matches]

% rm !$

这样可以检查通配符扩展,然后使用完全相同的glob模式,而不必在之前插入空格*

我也建议人们不要在具有破坏性的命令行上剪切和粘贴通配符模式。因为在我自己手中这一直是个问题:)

我实验室的一位技术人员上周(工作了3个月)才犯了这个错误-是的,我们有一个备份(落后了1天)。


0

每个人似乎都在说:“请多加注意”,“不要发出别名/确认提示,因为您会习惯于不适当注意它”。

酷,一切。我的意思是,我认为您不应该为它起别名rm(nor rmrf,因为您可以轻松地将其弄乱并键入真实命令)。

但是为什么不能创建一个别名/脚本并称其为remove仅提供一个参数(例如$ 1)呢?通配符应为$ 2,因为空格不正确(正确吗?),因此您的脚本/包装器/别名不会被送入第二个。是的,您一次只能执行一组删除操作(使用通配符),但这就是您要付出的代价。

如果我写的东西不错,我可能会让它告诉我计划删除的文件和目录的数量,以及正在删除的内容的总大小,然后要求确认,但这可能会妨碍您的访问。也许在那做一个标志选项remove?(-一世)。您可能还希望检查$ 1以查看它是否只是一个通配符并要求确认,并列出您实际所在的目录。


顺便说一句,那里有许多rm替代品。许多人试图与UI桌面垃圾兼容。其中一些可能值得研究。


6
您的“删除”别名永远不会一次删除多个文件。您不能使用通配符,因为外壳程序会在命令看到它之前对其进行扩展。
hymie 2015年

因此,对它进行评估,然后将其放入脚本中?
user3082

所以你想输入remove \*?如果您的脚本允许shell扩展其输入,我认为它没有太大帮助。
彼得·科德斯

0

一个非常简单的技巧是放在-rf结尾处:rm whatever* -rf
这样可以大大降低错误率,因为您在后面键入了更多字符*,因此您有更多的时间来查看错别字。
这不能解决所有问题。只是一个简单的日常技巧。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.