cp -R mq-airflow/ projects/ilearn/
你的意图是把 mq-airflow 整个文件夹复制到 projects/ilearn/ 下面,得到
projects/ilearn/mq-airflow/。
但在 macOS 上,实际结果是 mq-airflow 里面的所有文件被直接散进了
projects/ilearn/,根本没有 mq-airflow 这个文件夹。
罪魁祸首就是源路径后面那一个斜杠。
cp -R mq-airflow projects/ilearn/
两个注意点:
projects/ilearn/ 必须已经存在。否则 cp 会创建一个叫 ilearn 的副本,
而不是复制进它。先跑 mkdir -p projects/ilearn。给目标加斜杠是有好处的
—— 它会让 cp 明确报错,而不是悄悄做错事。如果 projects/ilearn/mq-airflow 已经存在,cp -R 是合并进去,不是替换,
旧文件会残留。想要干净的副本,先删掉目标,或者用 rsync:
rsync -a --delete mq-airflow/ projects/ilearn/mq-airflow/
注意 rsync 的规则正好相反 —— 那里源路径的斜杠是你需要的。
POSIX 规定:路径末尾的 / 等于在后面加了一个 .
所以 foo/ 实际上等于 foo/.。这带来两个后果。
touch f # 建一个普通文件
cat f # 正常
cat f/ # 报错:Not a directory
f/. 要求 f 是目录,但它是文件,所以失败。
mkdir realdir && ln -s realdir link
ls -ld link # 显示链接本身
ls -ld link/ # 显示它指向的目录
这一点很危险:
rm link # 只删链接,realdir 安全
rm link/ # 报错 —— 它是个目录
rm -rf link/ # 历史上会删掉 realdir 里面的内容
Tab 补全经常自动帮你加斜杠,很多人就是这样删错东西的。
cp(macOS / BSD 版)源路径加斜杠 = 「复制里面的内容」
cp -R mq-airflow/ projects/ilearn/ # 内容散进 ilearn/
cp -R mq-airflow projects/ilearn/ # 生成 ilearn/mq-airflow/
⚠️ Linux 上的 GNU
cp不是这样的,它基本忽略这个斜杠,两种写法结果一样。 所以同一条命令在你的 Mac 和服务器上可能结果不同。
不确定的时候先测一下:
mkdir -p t/src/sub t/dest && touch t/src/a
cp -R t/src/ t/dest/ && find t/dest
rsync(规则正好相反)| 写法 | 含义 |
|---|---|
rsync -a src/ dest/ |
复制 src 的内容 |
rsync -a src dest/ |
复制 src 这个目录本身 |
目标加不加斜杠无所谓。配合 --delete 时斜杠写错是经典的删库事故。
mv基本只遵循内核规则。mv a b/ 要求 b 必须已存在且是目录 —— 这是个不错的安全
习惯,写错时会报错,而不是悄悄把 a 改名成 b。
ln -s如果 link 是目录,ln -s target link/ 会把链接建在 link 里面。
findfind dir/ 和 find dir 在是否跟随顶层软链接上有区别,输出的路径也不一样。
.gitignore —— build 匹配文件和目录;build/ 只匹配目录COPY —— COPY src /dest 和 COPY src/ /dest/ 结果不同proxy_pass —— 末尾有没有 / 决定是否剥掉 location 前缀,
非常容易踩坑/about 和 /about/ 严格来说是两个不同资源,影响相对链接的解析给目标加斜杠会让 cp/mv 在目标不存在时明确报错,而源路径加斜杠才是歧义
的来源。所以:
给目标加斜杠,不给源加斜杠 —— 除了用
rsync的时候,那时要故意给源加斜杠。
mkdir /tmp/slashlab && cd /tmp/slashlab
在里面把各种组合都跑一遍,每次用 find . 看结果。花十分钟实验比看文档有用得多,
而且不会误删真实文件。
如果你正在收拾一开始那个失误:先 ls mq-airflow 和 projects/ilearn/ 对比一下,
再删任何东西。