03 文件和目录操作
学习目标
- 能新建文件和目录。
- 能复制、移动、重命名和删除文件。
- 能查看文件类型和文件详细状态。
命令总览
| 命令 | 用途 | 含义 | 基本用法 | 例子 |
|---|---|---|---|---|
touch | 创建空文件或更新时间 | 如果文件不存在就创建,存在则更新时间戳 | touch 文件名 | touch notes.txt |
mkdir | 创建目录 | make directory,创建文件夹 | mkdir [选项] 目录名 | mkdir -p logs/2026 |
cp | 复制文件或目录 | copy,把源复制到目标 | cp 源 目标 | cp a.txt b.txt |
mv | 移动或重命名 | move,把源移动到目标,也可用于改名 | mv 源 目标 | mv old.txt new.txt |
rm | 删除文件或目录 | remove,删除指定路径 | rm 文件 | rm old.txt |
file | 判断文件类型 | 根据内容判断文件格式 | file 文件 | file app.log |
stat | 查看文件详细信息 | 显示大小、权限、时间等元数据 | stat 文件 | stat app.log |
常用场景
下面是一段完整的受控实验,不依赖名为 project 的既有目录。它创建唯一临时目录、核对绝对路径与所有权,再演示创建、复制、移动和删除一个明确文件:
if [ "$(id -u)" -eq 0 ]; then
printf 'do not run this lab as root\n' >&2
exit 1
fi
lab_root=$(realpath -e -- "${TMPDIR:-/tmp}") || exit 1
home_real=$(realpath -e -- "${HOME:?HOME is required}") || exit 1
current_real=$(pwd -P)
paths_overlap_tree() {
if [ "$1" = '/' ] || [ "$2" = '/' ]; then
return 0
fi
case "$1/" in "$2/"*) return 0 ;; esac
case "$2/" in "$1/"*) return 0 ;; esac
return 1
}
if [ "$lab_root" = '/' ] \
|| paths_overlap_tree "$lab_root" "$home_real" \
|| paths_overlap_tree "$lab_root" "$current_real"; then
printf 'unsafe lab root overlaps home or working tree: %s\n' "$lab_root" >&2
exit 1
fi
work=$(mktemp -d "$lab_root/file-ops.XXXXXX") || exit 1
work_real=$(realpath -e -- "$work") || exit 1
case "$work_real" in
"$lab_root"/file-ops.*) ;;
*) printf 'unexpected work path: %s\n' "$work_real" >&2; exit 1 ;;
esac
if [ ! -O "$work" ] || [ -L "$work" ]; then
printf 'work ownership or symlink check failed\n' >&2
exit 1
fi
cd -- "$work_real" || exit 1
[ "$(pwd -P)" = "$work_real" ] || exit 1
mkdir -p -- project/data/raw project/data/processed project/logs
touch -- project/README.md
cp -- project/README.md project/README.bak.md
cp -R -- project/data project/data_backup
mv -- project/README.bak.md project/backup.md
mv -- project/backup.md project/logs/
target=$(realpath -e -- "$work_real/project/logs/backup.md") || exit 1
case "$target" in
"$work_real"/project/logs/backup.md) ;;
*) printf 'unexpected target: %s\n' "$target" >&2; exit 1 ;;
esac
printf 'delete=%s\n' "$target"
rm -- "$target"
file -- project/README.md
stat -- project/README.md
find . -maxdepth 3 -print递归删除的签名只作参考:rm -r -- "$directory"。课程不提供可直接复制的 rm -rf,因为它会绕过部分交互和不存在文件的提示,且默认 --preserve-root 只特别保护 /,不能保护家目录、挂载点或错误变量。实验目录保留供检查,不自动递归删除。
新手注意
rm删除后通常不会进回收站,执行前要确认路径。rm -rf非常危险,尤其不要对/、~、空变量拼出来的路径使用。- 复制目录的 POSIX 便携选项是
cp -R;GNU 常见-r,但脚本应按目标平台核对。 mv既能移动文件,也能重命名文件;目标是已有目录时表示移动进去。- 使用带空格的文件名时要加引号,例如
mv "old name.txt" "new name.txt"。 --结束选项解析,可保护以-开头的路径;变量仍必须双引号引用。- 递归操作还要检查符号链接、挂载点与预期根目录;不要默认 sudo。
安全练习与验收
运行上面的完整实验,核对输出路径符合 $TMPDIR/file-ops.*、目标属于当前用户且不是符号链接。保存 pwd -P、find . -maxdepth 3 -print 和退出码;确认只删除了 project/logs/backup.md,不练递归删除。