linux中处理文件名的首选方法

超级欧派课程 2024-03-07 03:35:20

处理任意文件名的首选方法仍然是使用 find(1):

find ... -exec command {} \;

或者,如果你需要批量处理文件名:

find ... -exec command {} +

xargs 很少比上述方法更有用,但如果你真的坚持要使用,记住要使用 -0(-0 不在 POSIX 标准中,但由GNU和BSD系统实现):

# 需要GNU/BSD的find和xargsfind ... -print0 | xargs -r0 command# 永远不要在没有 -0 或类似扩展的情况下使用xargs!

除非你真的不能使用上述方法,否则请使用其中之一。

处理文件名中包含空格的另一种方法是使用shell的文件名扩展(globbing)。它的缺点是不能递归工作(除非使用zsh的扩展或bash 4的globstar),通常不包括隐藏文件(以 "." 开头的文件名)。但是,如果你只需要处理单个目录中的所有文件,并且可以忽略隐藏文件,那么这种方法非常有效。

例如,下面的代码将当前目录中所有的 *.mp3 文件的文件名中的空格替换为下划线(这使用了bash/ksh的扩展,允许在参数扩展中使用 "/"):

# Bash/kshfor file in ./*\ *.mp3; do if [ -e "$file" ] ; then # 确保它不是一个空匹配 mv "$file" "${file// /_}" fidone

如果你确定至少有一个路径与通配符匹配,你可以省略 "if..." 和 "fi" 行。问题是,如果通配符不匹配,循环不会像你预期的那样执行0次,而是会执行一次,使用未扩展的模式(通常不是你想要的)。你还可以使用bash的扩展 "shopt -s nullglob",使空的通配符扩展成空,然后你可以再次省略 if 和 fi。

记住,你需要用双引号引用所有的参数。如果不这样做,扩展将经历WordSplitting(参见argument splitting和BashPitfalls)。另外,始终在通配符前加上 "/" 或 "./",否则,如果有一个以 "-" 开头的文件,扩展可能会被错误解释为选项。

处理文件名的另一种递归方法是使用 find 的 -print0 选项(GNU/BSD 扩展),以及bash的 -d 扩展选项与 read 结合使用:

# Bashunset a iwhile IFS= read -r -d $'\0' file; do a[i++]="$file" # 或者你想要如何处理每个文件done < <(find /tmp -type f -print0)

上面的示例将 /tmp(递归地)下的所有文件(即使它们的名称中包含换行符或其他空白字符)读入一个数组中,通过强制 read 使用 NUL字节(\0)作为行分隔符。由于 NUL 在 Unix 文件名中不是有效的字节,所以这是除了使用 find -exec 之外最安全的方法。需要使用 IFS= 来避免修剪前导/尾随空白,并且需要使用 -r 来避免反斜杠处理。实际上,$'\0' 实际上是空字符串(bash 不支持将 NUL 字节传递给命令,即使是内置命令),所以我们也可以这样写:

# Bashunset a iwhile IFS= read -r -d '' file; do a[i++]="$file"done < <(find /tmp -type f -print0)

那么,为什么下面的代码不起作用?

# 不起作用unset a ifind /tmp -type f -print0 | while IFS= read -r -d '' file; do a[i++]="$file"done

由于管道,整个循环在一个子shell中执行,因此循环终止后数组赋值将丢失。

为了解决这个问题,可以使用进程替代(Process Substitution)或使用命令组(Command Group),如果对这两个不了解可以文末进入我的《shell脚本编程最佳实践》专栏学习一下,

使用进程替代:# 使用进程替代unset a iwhile IFS= read -r -d '' file; do a[i++]="$file"done < <(find /tmp -type f -print0)使用命令组:# 使用命令组unset a i{ while IFS= read -r -d '' file; do a[i++]="$file" done} < <(find /tmp -type f -print0)

这样,循环执行在当前shell中,而不是在子shell中,使得数组赋值不会丢失。

如果您觉得文章内容对你有一点帮助可以关注我,我在头条平台会持续分享更多实用的shell技巧和最佳实践,如果想系统的快速学习shell的各种高阶用法和生产环境避坑指南可以看看《shell脚本编程最佳实践》专栏,专栏里有更多的实用小技巧和脚本代码分享。

0 阅读:0

超级欧派课程

简介:感谢大家的关注