KSH脚本中批量移动带日期后缀文件到目录的解决方案


阅读 2 次

问题重现

在Unix/Linux环境下使用Korn Shell(ksh)脚本处理文件时,经常会遇到需要按日期后缀批量移动文件的需求。比如以下典型场景:

for file in $fileDirectory/*.$yesterdayDate
do
mv *.$yesterdayDate "$fileDirectory/$yesterdayDate"
done

错误分析

执行时出现的错误提示表明脚本无法找到匹配的文件:

mv: cannot stat ‘*.20200607’: No such file or directory

主要原因在于循环体内重复使用通配符*.$yesterdayDate,而Shell在执行前会先展开通配符。当目录中没有匹配文件时,通配符会保持原样传递给mv命令。

正确实现方式

以下是几种可靠的实现方案:

方案1:使用find命令

find "$fileDirectory" -maxdepth 1 -name "*.$yesterdayDate" \\
-exec mv {} "$fileDirectory/$yesterdayDate/" \\;

方案2:优化后的ksh循环

mkdir -p "$fileDirectory/$yesterdayDate"
for file in "$fileDirectory"/*."$yesterdayDate"; do
  [ -e "$file" ] || continue
  mv "$file" "$fileDirectory/$yesterdayDate/"
done

方案3:使用nullglob选项

set -o nullglob
files=("$fileDirectory"/*."$yesterdayDate")
(( ${#files[@]} )) && mv "${files[@]}" "$fileDirectory/$yesterdayDate/"

最佳实践建议

  • 始终用双引号包裹变量引用
  • 先检查目标目录是否存在
  • 处理前验证文件是否存在
  • 考虑添加错误处理逻辑

完整示例脚本

#!/bin/ksh

fileDirectory="/path/to/files"
yesterdayDate=$(date +%Y%m%d -d "yesterday")

# 创建目标目录
mkdir -p "$fileDirectory/$yesterdayDate" || {
  echo "无法创建目录" >&2
  exit 1
}

# 移动文件
set -o nullglob
files=("$fileDirectory"/*."$yesterdayDate")
if (( ${#files[@]} )); then
  mv "${files[@]}" "$fileDirectory/$yesterdayDate/"
  echo "成功移动 ${#files[@]} 个文件"
else
  echo "未找到匹配文件"
fi