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

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

从来没想过这种事会发生在我身上,但就是这样。¯\_(ツ)_/¯

我从错误目录内的存储库运行了构建脚本,而没有先查看源代码。这是脚本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

危险的部分似乎是

mkdir -p cmake-build-local
cd cmake-build-local
rm -rf *

但转念一想,似乎也确实不可能出错。

您应该运行此脚本的方式是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

.config以及一些标准 XDG 目录(例如图片和桌面)都消失了,但 .bashrc 仍然存在。.nix-channels仍然在那里,但.nix-defexpr被核武器摧毁了。

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

  1. 什么地方出了错?我想修复此构建脚本并制作 PR 以防止将来发生这种情况。
  2. 文件被删除的顺序是什么?显然不是按字母顺序排列,而是*按字母顺序展开,所以看起来这里发生了其他事情。

答案1

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

什么地方出了错?

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

cd ../Dependencies/cpython

失败,因为没有../Dependencies

mkdir debug
cd debug

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

../configure --with-pydebug --enable-shared
make

不执行任何操作,因为没有../configuremake

cd ../../..
cd ..

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

mkdir -p cmake-build-local

这会失败,因为您没有写入/或 的权限/home

cd cmake-build-local

由于没有目录,因此失败cmake-build-local

我们现在要……

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

rm -rf *

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

如何修复脚本

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

(脚本也应该以舍邦行来指示要使用哪个 shell,例如#!/bin/sh#!/bin/bash。但这对解决这个问题没有帮助。)

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

mkdir -p cmake-build-local
cd cmake-build-local
rm -rf *

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

rm -rf cmake-build-local
mkdir cmake-build-local
cd cmake-build-local

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

答案2

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

cd ../Dependencies/cpython

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

mkdir debug
cd debug

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

cd ../../..

我们现在在~/Distribution.

cd ..

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

mkdir -p cmake-build-local
cd cmake-build-local

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

cd ..

我们现在回到您的主目录

cd Distribution

我们现在在~/Distribution.

cd ..
cd Scripts

我们现在处于~/Scripts(您会因此得到一个错误,因为您比您预期的级别高一级)。


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

cd ../Dependencies/cpython

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

mkdir debug
cd debug

你现在在~/Distribution/debug.

cd ../../..

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

cd ..

你很可能/现在就在。

cd Distribution
mkdir -p cmake-build-local
cd cmake-build-local

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

rm -rf *

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

命令行上列出的参数rm将按照扩展它们的顺序进行处理*(字典顺序,即,binbootcdromdevetc等)。然后列出的每个目录将按照“目录顺序”(未排序)进行递归处理。


你应该做什么:

#!/bin/sh

topdir=$HOME/Distribution

mkdir -p "$topdir/Dependencies/cpython/debug"
(
    cd "$topdir/Dependencies/cpython/debug" || exit 1

    ../configure --with-pydebug --enable-shared
    make
)

rm -rf "$topdir/cmake-build-local"
mkdir -p "$topdir/cmake-build-local"
(
    cd "$topdir/cmake-build-local" || exit 1

    cmake .. -DMVDIST_ONLY=True -DMVPY_VERSION=0 -DMVDPG_VERSION=local_build
    make -j
)

(
    cd "$topdir" || exit 1

    python3 BuildPythonWheel.py ../cmake-build-local/[redacted]/core.so 0
    python3 -m ensurepip
    python3 -m pip install --upgrade pip
    python3 -m setup bdist_wheel --plat-name manylinux1_x86_64 --dist-dir ../dist
)

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

答案3

如果脚本假设它是从 inside 运行的Scripts,那么这些都不会执行脚本作者的预期:

cd ../Dependencies/cpython
mkdir debug
cd debug
cd ../../..
cd ..
mkdir -p cmake-build-local
cd cmake-build-local

第一个cd会失败,第二个cd会移动到一个文件夹中,然后可能会将 cd ../../..cd ..放在主目录上方的某个位置(可能在该/home目录中,您通常无权在其中创建任何内容,因此mkdir后续cd会失败)。然后*可能扩展到您的主目录,因此rm -rf对其进行操作,递归到内容,这将解释删除的随机顺序(目录条目不按任何特定顺序排序)。

相关内容