如何使用awk打印包含空格字符的空格分隔字段
问题根源
原命令从设计上就处理不了带空格的文件名,核心问题有两个:
ls -al是给人看的格式化输出,根本不是给脚本做解析用的。长格式输出里文件名确实从第9列开始,但只要文件名里带空格,就会被空格拆成多个字段,awk取$9只能拿到空格前的半截文件名。- 不带参数的
xargs默认把所有空白字符(空格、制表符、换行)当成分隔符,就算前面能拿到完整文件名,xargs也会把空格前后拆成两个独立参数传给后续命令。
正确实现方案
方案1:兼容性最好、支持所有合法文件名
用find搭配null分隔符处理,从根本上避免特殊字符分割错误,可完美适配带空格、换行、特殊符号的文件名。只处理当前目录下所有文件/文件夹(包含隐藏文件,不递归子目录)的写法:
find . -maxdepth 1 -mindepth 1 -print0 | xargs -0 do_something
参数说明:
-maxdepth 1 -mindepth 1:限定只遍历当前目录的直接内容,排除当前目录.本身,也不会递归进入子文件夹-print0:让find输出的每个文件路径以null字符作为分隔符,null是类Unix系统文件名中永远不可能出现的字符,不存在分割歧义xargs -0:和前面的-print0配对,按null字符拆分输入项,无论文件名带什么特殊字符都不会拆分错误- 如果
do_something一次只支持接收一个文件参数,给xargs加上-n1参数即可,即find . -maxdepth 1 -mindepth 1 -print0 | xargs -0 -n1 do_something - 如果需要递归处理当前目录下所有层级的文件/文件夹(含隐藏文件),直接去掉
-maxdepth 1 -mindepth 1参数即可。
方案2:Shell原生循环写法(bash/zsh环境适用)
不需要依赖find,通过开启shell的隐藏文件匹配选项直接遍历处理:
# bash环境执行,开启隐藏文件匹配 shopt -s dotglob for entry in *; do do_something "$entry" done
注意遍历拿到的$entry变量必须加双引号包裹,双引号会保留变量值里的空格,不会被shell拆分成多个参数。zsh环境默认就支持匹配隐藏文件,不需要执行shopt命令,直接写循环即可。
注意事项
不要在脚本里解析ls的输出是shell编写的基本常识:ls的输出格式受环境变量、版本、终端配置影响很大,且天生无法正确处理带空格、换行、控制字符的文件名,属于典型的反模式,只要涉及文件名处理都应该避开这种写法。
内容的提问来源于stack exchange,提问作者khteh
相关产品推荐
相关产品推荐

