![将 bash 脚本中的文件移动到从文件名中提取的子目录](https://linux22.com/image/198140/%E5%B0%86%20bash%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E7%9A%84%E6%96%87%E4%BB%B6%E7%A7%BB%E5%8A%A8%E5%88%B0%E4%BB%8E%E6%96%87%E4%BB%B6%E5%90%8D%E4%B8%AD%E6%8F%90%E5%8F%96%E7%9A%84%E5%AD%90%E7%9B%AE%E5%BD%95.png)
我有一个包含一堆备份文件的目录,如下所示:
projectA20210901.gz
projectA20210902.gz
projectB20210901.gz
projectB20210902.gz
我想将所有文件移动到projectA*
创建子目录(如果它们尚不存在)。./projectA/
projectB*
./projectB/
日期之前的项目名称2021...
各不相同,需要从文件名中提取,但日期始终存在且始终以202
2021、2022 等开头 - 我们不必担心 2029 年之后会发生什么 :)
参数扩展可用于提取项目名称,这将是子目录名称:
$ string=projectA20211103-23.gz
$ echo ${string%202*}
projectA
如何将其放入脚本中以对当前目录中的所有文件运行?应忽略文件夹和符号链接。
答案1
你的第一步是好的。尝试find
在 bash shell 中使用并通过管道传输其结果,如下所示:
$ find . -maxdepth 1 -iname "project?202?????.gz" -print0 | xargs -0 -I {} bash -c '
var="$1";
var1="${var%%202*}";
mkdir -p "$var1";
echo mv "$var" "$var1"' xargs_bash {}
mv ./projectB20210901.gz ./projectB
mv ./projectA20210901.gz ./projectA
mv ./projectB20210902.gz ./projectB
mv ./projectA20210902.gz ./projectA
评论:
- 您可以将上面的一行写在一行上。
- 一旦您对输出与
mv
您想要发出的命令相对应感到满意,只需从要执行的移动的一行中删除“echo”命令即可。 - 我的目的并不在于简洁;我喜欢可读性。
怎么运行的:
find
查看当前目录并从那里沿着树向下查找。-maxdepth 1
告诉 find 将其搜索限制在当前目录,即不沿着树向下搜索。-iname
根据以下模式以独立于大小写的方式查找文件名- 文件名模式使用特殊字符:
?
表示任意一个字符、*
表示任意数量的字符 print0
输出结果在每个结果的末尾放置一个 \0 空字符,而不是标准的换行符。这是为了考虑到有时文件名包含换行符。xargs -0
在管道识别出输出中的每个文件名与下一个文件名之间用空字符分隔之后xargs bash -c '...'
生成一个 bash shell,其作用是根据需要处理每个输出find
,基于字符串操作,根据需要创建子目录 (mkdir -p
),最后根据请求将每个文件移动到子目录。
所以最后一个没有 cmd 的一行echo
是:
$ find . -maxdepth 1 -iname "project?202?????.gz" -print0 | xargs -0 -I {} bash -c 'var="$1"; var1="${var%%202*}"; mkdir -p "$var1"; mv "$var" "$var1"' xargs_bash {}
HTH。
答案2
另一种方法是:
cd /mybackups
for file in *;
do
if [ -f "$file" ]; then
newdir=${file%202*}
mkdir -p "$newdir"
mv "$file" "${newdir}"
fi
done