我刚刚删除了主目录中的所有内容。如何?为什么有些文件仍然存在?

iFr*_*cht 32 bash zsh shell-script rm deleted-files

从未想过这会发生在我身上,但你去了。 ¯\_(?)_/¯

我从错误目录中的存储库中运行了一个构建脚本,而没有先查看源代码。这是脚本Scripts/BuildLocalWheelLinux.sh

cd ../Dependencies/cpython
mkdir debug
cd debug
../configure --with-pydebug --enable-shared
make
cd ../../..

cd ..
mkdir -p cmake-build-local
cd cmake-build-local
rm -rf *
cmake .. -DMVDIST_ONLY=True -DMVPY_VERSION=0 -DMVDPG_VERSION=local_build
make -j
cd ..

cd Distribution
python3 BuildPythonWheel.py ../cmake-build-local/[redacted]/core.so 0
python3 -m ensurepip
python3 -m pip install --upgrade pip
[more pip install stuff]
python3 -m setup bdist_wheel --plat-name manylinux1_x86_64 --dist-dir ../dist
cd ..
cd Scripts
Run Code Online (Sandbox Code Playgroud)

危险的部分似乎是

mkdir -p cmake-build-local
cd cmake-build-local
rm -rf *
Run Code Online (Sandbox Code Playgroud)

不过仔细一想,好像也不会出错。

您应该运行此脚本的方式是cd Scripts; ./BuildLocalWheelLinux.sh. 当我第一次运行它时,它在最后一行显示错误(我后来了解到)。我很着急,所以我虽然“也许文档已经过时了,我会尝试从项目根目录运行。所以我跑了./Scripts/BuildLocalWheelLinux.sh。突然,vscodes 主题和缩放​​级别发生了变化,我的 zsh 终端配置被重置,终端字体被设置为默认值,一旦我意识到发生了什么,我就按 Ctrl+C。

还剩下一些文件,但它们没有明显的模式:

$ ls -la
total 216
drwx------ 27 felix   felix   4096 May 12 18:08 .
drwxr-xr-x  3 root    root    4096 Apr 15 16:39 ..
-rw-------  1 felix   felix  12752 Apr 19 11:07 .bash_history
-rw-r--r--  1 felix   felix   3980 Apr 15 13:40 .bashrc
drwxrwxrwx  7 felix   felix   4096 May 12 18:25 .cache
drwx------  8 felix   felix   4096 May 12 18:26 .config
drwx------  3 root    root    4096 Apr 13 21:40 .dbus
drwx------  2 felix   felix   4096 Apr 30 12:18 .docker
drwxr-xr-x  8 felix   felix   4096 Apr 15 13:40 .dotfiles
-rw-------  1 felix   felix   8980 Apr 13 18:10 examples.desktop
-rw-r--r--  1 felix   felix    196 Apr 19 15:19 .gitconfig
-rw-r--r--  1 felix   felix     55 Apr 16 13:56 .gitconfig.old
-rw-r--r--  1 felix   felix   1040 Apr 15 13:40 .gitmodules
drwx------  3 felix   felix   4096 May  6 10:10 .gnupg
-rw-r--r--  1 felix   felix   1848 May  5 14:24 heartbeat.tcl
-rw-------  1 felix   felix   1610 Apr 13 20:36 .ICEauthority
drwxr-xr-x  5 felix   felix   4096 Apr 21 16:39 .ipython
drwxr-xr-x  2 felix   felix   4096 May  4 09:35 .jupyter
-rw-------  1 felix   felix    161 Apr 27 14:23 .lesshst
drwx------  3 felix   felix   4096 May 12 18:08 .local
-rw-r--r--  1 felix   felix    140 Apr 29 17:54 minicom.log
drwx------  5 felix   felix   4096 Apr 13 18:25 .mozilla
drwxr-xr-x  2 felix   felix   4096 Apr 13 18:10 Music
drwxr-xr-x  6 felix   felix   4096 May 12 17:16 Nextcloud
-rw-r--r--  1 felix   felix     52 Apr 16 11:43 .nix-channels
-rw-------  1 felix   felix   1681 Apr 20 10:33 nohup.out
drwx------  3 felix   felix   4096 Apr 15 11:16 .pki
-rw-------  1 felix   felix    946 Apr 16 11:43 .profile
drwxr-xr-x  2 felix   felix   4096 Apr 13 18:10 Public
drwxr-xr-x  2 felix   felix   4096 May 12 18:08 .pylint.d
-rw-------  1 felix   felix   1984 May 12 18:06 .pythonhist
-rw-r--r--  1 felix   felix   2443 Apr 19 13:40 README.md
drwxr-xr-x 13 felix   felix   4096 May 12 18:08 repos
drwxr-xr-x  6 felix   felix   4096 Apr 19 11:08 snap
drwx------  3 felix   felix   4096 May  5 15:33 .ssh
drwxr-xr-x  5 felix   felix   4096 Apr 26 17:39 .stm32cubeide
drwxr-xr-x  5 felix   felix   4096 May  5 15:52 .stm32cubemx
drwxr-xr-x  2 felix   felix   4096 Apr 23 11:44 .stmcube
drwxr-xr-x  2 felix   felix   4096 Apr 13 18:10 Templates
drwxr-xr-x  3 felix   felix   4096 Apr 19 11:57 test
drwxr-xr-x  2 felix   felix   4096 Apr 13 18:10 Videos
-rw-------  1 felix   felix  14313 May 12 10:45 .viminfo
-rw-r--r--  1 felix   felix    816 Apr 15 13:40 .vimrc
drwxr-xr-x  3 felix   felix   4096 Apr 16 12:08 .vscode
-rw-r--r--  1 felix   felix   2321 Apr 19 18:47 weird_bug.txt
-rw-r--r--  1 felix   felix    162 Apr 15 13:40 .xprofile
Run Code Online (Sandbox Code Playgroud)

.config消失了,还有一些标准的 XDG 目录,如图片和桌面,但 .bashrc 仍然存在。.nix-channels还在那里,但.nix-defexpr被核弹了。

所以,这让我想到两个问题:

  1. 什么地方出了错?我想修复这个构建脚本并进行 PR 以防止将来发生这种情况。
  2. 文件是按什么顺序删除的?显然不是按字母顺序,而是按字母顺序*扩展,所以这里似乎发生了其他事情。

Gil*_*il' 68

哎哟。你不是第一个受害者

什么地方出了错?

从您的主目录开始,例如/home/felix,甚至在/home/felix/src或 中/home/felix/Downloads/src

cd ../Dependencies/cpython
Run Code Online (Sandbox Code Playgroud)

失败,因为没有../Dependencies.

mkdir debug
cd debug
Run Code Online (Sandbox Code Playgroud)

您现在位于debug您开始的目录的子目录中。

../configure --with-pydebug --enable-shared
make
Run Code Online (Sandbox Code Playgroud)

什么都不做,因为没有../configureor make

cd ../../..
cd ..
Run Code Online (Sandbox Code Playgroud)

如果您开始的目录深度不超过三层,cd debug到了第四层,则当前目录现在是根目录。如果您从四个目录级别开始,当前目录现在是/home.

mkdir -p cmake-build-local
Run Code Online (Sandbox Code Playgroud)

这将失败,因为您无权写入//home

cd cmake-build-local
Run Code Online (Sandbox Code Playgroud)

这失败了,因为没有目录cmake-build-local

我们现在要……

文件是按什么顺序删除的?

rm -rf *
Run Code Online (Sandbox Code Playgroud)

这会尝试递归删除当前目录中的每个文件,即//home。主目录按字母顺序枚举,但下面的文件按目录遍历的任意顺序枚举。它的顺序与ls --sort=none(除非rm出于某种原因决定使用不同的顺序)。请注意,此顺序通常不会保留在备份中,并且可以在目录中创建或删除文件时更改。

如何修复脚本

首先,几乎所有的 shell 脚本都应该set -e在顶部附近。set -e如果命令失败,将导致脚本中止。(如果退出状态非零,则命令失败。)set -e不是万能药,因为在某些情况下它不会生效。但这是您可以期望的最低限度,它会在这里做正确的事情。

(此外,脚本应该以shebang行开头,以指示使用哪个 shell,例如#!/bin/sh#!/bin/bash。但这对解决这个问题没有帮助。)

rm -rf *,或类似rm -rf $foo.*(如果$foo结果是空的怎么办?)的变体,都是脆弱的。在这里,而不是

mkdir -p cmake-build-local
cd cmake-build-local
rm -rf *
Run Code Online (Sandbox Code Playgroud)

删除并重新创建目录会更健壮。(这不会保留目录的权限,但在这里这不是问题。)

rm -rf cmake-build-local
mkdir cmake-build-local
cd cmake-build-local
Run Code Online (Sandbox Code Playgroud)

另一种方法对于删除错误的文件更健壮,但对于要删除的丢失文件更脆弱:仅删除已知已构建的文件,通过运行make clean具有rm已知构建目标和已知扩展名(例如,rm *.o可以)的命令。

  • 完美答案!我已经提交了 PR。 (11认同)
  • 大约 5 小时后,PR 获得批准并合并。一定要喜欢开源。 (11认同)
  • @iFreilicht“必须喜欢开源”。除非拙劣的脚本删除了您的主文件夹。 (4认同)
  • `set -eo pipefail` 修复了 `set -e` 的大部分缺点。 (2认同)
  • @KonradRudolph 不,函数 _is_ 中的失败被忽略了!它不会使条件为假。这是一个没有函数`sh -c 'set -e 的简单案例;如果是假的;真的; 然后回声哎呀;fi`'(在现实世界中,失败的命令通常隐藏在一个函数中,这使得它很难找到。)。至于`pipefail`,不使用它的原因是不是所有的shell都有它。 (2认同)

Kus*_*nda 11

跟踪您的cd调用,假设我们正在运行脚本~/Distribution/Scripts并假设每个都cd成功:

cd ../Dependencies/cpython
Run Code Online (Sandbox Code Playgroud)

我们现在在~/Distribution/Dependencies/cpython.

mkdir debug
cd debug
Run Code Online (Sandbox Code Playgroud)

我们现在在~/Distribution/Dependencies/cpython/debug.

cd ../../..
Run Code Online (Sandbox Code Playgroud)

我们现在在~/Distribution.

cd ..
Run Code Online (Sandbox Code Playgroud)

我们现在在您的主目录中。

mkdir -p cmake-build-local
cd cmake-build-local
Run Code Online (Sandbox Code Playgroud)

我们现在在~/cmake-build-local. 这是你运行的地方rm -rf *

cd ..
Run Code Online (Sandbox Code Playgroud)

我们现在回到您的主目录

cd Distribution
Run Code Online (Sandbox Code Playgroud)

我们现在在~/Distribution.

cd ..
cd Scripts
Run Code Online (Sandbox Code Playgroud)

我们现在进入了~/Scripts(你会因此得到一个错误,因为你比你预期的要高一级)。


接着。您尝试运行相同的脚本,但从~/Distribution.

cd ../Dependencies/cpython
Run Code Online (Sandbox Code Playgroud)

这失败了。这让您仍然处于~/Distribution.

mkdir debug
cd debug
Run Code Online (Sandbox Code Playgroud)

你现在在~/Distribution/debug.

cd ../../..
Run Code Online (Sandbox Code Playgroud)

您现在在~/..(可能在/home)。

cd ..
Run Code Online (Sandbox Code Playgroud)

你现在很可能在/

cd Distribution
mkdir -p cmake-build-local
cd cmake-build-local
Run Code Online (Sandbox Code Playgroud)

这些可能由于“没有这样的文件或目录”和“权限被拒绝”而失败。

rm -rf *
Run Code Online (Sandbox Code Playgroud)

您仍在/目录中,您的rm命令将尝试删除整个文件系统中的每个文件。权限仅允许删除位于您具有写入权限的目录中的文件,因此您可能只会丢失/tmp主目录中和主目录中的文件。

的命令行中列出的参数rm将被处理的是,为了*扩大它们(辞书,即binbootcdromdevetc,等等)将然后被递归处理中列出的每个目录,并且在“目录命令”(未排序)。


你应该做的:

cd ../Dependencies/cpython
Run Code Online (Sandbox Code Playgroud)

每个单独的( ... )子 shell 中的工作目录是该子 shell 的本地目录。cd子外壳中的初始值不会影响“外部”环境的工作目录。其余代码使用不依赖于用户 shell 会话的初始工作目录的绝对路径名。特别注意,该rm命令不会盲目扩展*,而是删除通过绝对路径指定的特定目录(如果该目录不存在,这不会出现严重错误)。


mur*_*uru 5

如果脚本假定它是从 inside 运行的Scripts,那么这些都不会按照脚本作者的意图执行:

cd ../Dependencies/cpython
mkdir debug
cd debug
cd ../../..
cd ..
mkdir -p cmake-build-local
cd cmake-build-local
Run Code Online (Sandbox Code Playgroud)

第一次cd失败,第二个cd移动到一个文件夹,那么 cd ../../..cd ..可能把你上方某处你的home目录(也许在/home目录中,其中你平时不有权做什么,所以mkdir和随后的cd失败)。然后*可能扩展到您的主目录,因此对其进行rm -rf操作,递归到内容中,这将解释删除的随机顺序(目录条目未按任何特定顺序排序)。