如何在Shell中将包含空格的子目录调整到列表首位
问题根因
你遇到的报错和逻辑问题核心来自两个错误用法:
- 用普通字符串变量存储
ls输出后直接用for I in $x遍历:shell会对未加引号的变量做分词和通配符展开,带空格的目录名会被拆分为多个独立的元素,比如Dir 3会被拆成Dir、3两个单独的循环项,这是你报错的直接原因。 sed命令使用逻辑完全错误:sed "/"$X"/d" "$I"里第二个参数被你传入了目录名,而sed是用来编辑文本内容的命令,它会尝试把你传入的目录名当成文本文件读取,自然会报「找不到文件」的错误,你想实现的「从列表中删除对应项」的逻辑完全不需要用sed实现。
最简解决方案
不需要用复杂的嵌套循环、ls、sed操作,直接用shell原生glob匹配就能安全实现需求,全程不会触发空格分词问题:
# 开启nullglob避免无匹配项时glob本身被当成字符串 shopt -s nullglob # 先输出所有带空格的子目录(自动排在顶部) for dir in */; do [[ $dir == *' '* ]] && echo "${dir%/}" done # 再输出所有不带空格的子目录 for dir in */; do [[ $dir != *' '* ]] && echo "${dir%/}" done
其中*/是匹配当前目录下所有子目录的glob规则,${dir%/}是用来去掉目录名末尾的/后缀,符合你要的输出格式。
如果你想修复原有写法的逻辑
如果要沿用你原本「先存全量目录、再存带空格目录」的思路,需要用数组来存储目录名,数组天然支持带空格的元素,不会触发分词:
shopt -s nullglob # 所有子目录存入数组x,自动去掉末尾/ x=(*/) x=("${x[@]%/}") # 带空格的子目录存入数组y y=() for d in "${x[@]}"; do [[ $d == *' '* ]] && y+=("$d") done # 先输出所有带空格的目录 printf "%s\n" "${y[@]}" # 再输出全量目录中不在y里的项 for d in "${x[@]}"; do [[ ! " ${y[*]} " =~ " $d " ]] && echo "$d" done
内容的提问来源于stack exchange,提问作者Alyssa Kowther
相关产品推荐
相关产品推荐

