我想复制单个目录中的多个文件。示例文件名以 开头error042021.mysite
,我希望新名称以 结尾-dev.co.at.txt
。我认为我需要数字通配符,因为数字会有所不同:022021
、032021
、042021
等。(数字=月份、年份)。
例如这就是我想要做的事情error042021.mysite.at.txt
:
cp -p error042021.mysite.at.txt error042021.mysite-dev.co.at.txt
我不想使用,mv
因为旧文件仍然保留。
我试过:
FILE=/srv/www/mysite.at/storage/logs/error/error??????.mysite.at.txt
if [[ -f "$FILE" ]]; then
echo "$FILE exists."
cp -p error??????.mysite.at.txt error??????.mysite-dev.co.at.txt
fi
或者说用起来更好吗sed
?
答案1
您的代码几乎没有问题。
FILE=/srv/www/mysite.at/storage/logs/error/error??????.mysite.at.txt
不会触发文件名生成。如果触发,您可能会得到多个结果。没有简单的方法可以将多个路径名存储在变量中,并能够可靠地逐个检索路径名。在 Bash 中,你可以使用数组:
FILE=( /srv/www/mysite.at/storage/logs/error/error??????.mysite.at.txt )
这会触发路径名生成并允许可靠地检索路径名。数组通常很有用,但在这种情况下不是必需的。要迭代扩展的结果,您不需要数组变量,您可以在循环中直接使用模式
for
:for f in /srv/www/mysite.at/storage/logs/error/error??????.mysite.at.txt; do …
数组是不可移植的,使用 with 中的模式
for
。您
[[ -f "$FILE" ]]
看起来像是在尝试查看文件是否存在。如果不是上述问题,这将是一个好主意。在我们的for f in …
循环中,我们需要一些类似的东西,因为error??????.mysite.at.txt
可能不匹配任何内容。如果它不匹配任何内容,那么它将保持原样(带有文字?
字符)。有几种方法可以解决这个问题:- 在 Bash 中
shopt -s nullglob
,使用模式之前调用的循环会在没有匹配项时将模式扩展为空字符串。在这种情况下,如果for
像上面一样使用模式,那么循环内部将执行零次,正如您所期望的那样。 - 或者您可以在循环内部测试它是否
$f
不是所使用的文字模式。 - 或者,您可以在循环内部测试是否
$f
是某个现有文件的路径名。原则上,这就是您尝试使用 所做的[[ -f "$FILE" ]]
。我更喜欢[
而[[
不是 就[
足够了,因为[
它是可移植的,而[[
不是。
可能还有其他合理的方法,其中一些方法特定于您想要做的事情。例如,您可以不关心并让其
cp
失败(可能默默地2>/dev/null cp …
:)。- 在 Bash 中
FILE
不是一个好的变量名。如果你习惯了大写名称,那么迟早你会覆盖你的PATH
。在脚本中使用名称一般采用小写形式:file
,,(f
path
zsh
虽然不在)、……在解析时
cp -p error??????.mysite.at.txt error??????.mysite-dev.co.at.txt
,shell 将扩展每个模式分别地。第一次和第二次出现的 之间没有任何联系??????
。假设脚本在正确的目录中,并且第一个模式扩展为某个内容,则第二个模式很可能会保持原样(或如果nullglob
处于活动状态则消失),因为没有匹配的文件。第一个模式可能首先扩展为多个路径名。在某些情况下,第二个模式可能扩展为一个或多个路径名。
在我们的
for
循环中,源路径名只是$f
(我们将正确引用)。我们需要制作一个正确的目标路径名。一般来说,这sed
可能是操纵路径名的正确工具;但在这种情况下,shell 就足够了,就像我的另一个答案. 我们将从 的扩展中获取正确的目标路径名${f%.at.txt}-dev.co.at.txt
。
我们的基本代码是:
#!/bin/sh
for f in /srv/www/mysite.at/storage/logs/error/error??????.mysite.at.txt; do
[ -f "$f" ] && cp -p -- "$f" "${f%.at.txt}-dev.co.at.txt"
done
笔记:
- 我用作
/bin/sh
shebang 是因为代码是完全可移植的。 - 我在生成路径名时使用了绝对路径,因此不需要
--
在调用 时cp
。我仍然决定把它放在那里以促进良好的做法。即使你选择cd /…/error
首先和for f in error??????.mysite.at.txt; do …
,那么扩展的字符串$f
永远不会以 开头-
,并且 的存在--
不会改变任何东西。但如果有人拿走这段代码并将其与类似模式一起使用,??????.mysite.at.txt
那么他们可能真的需要--
。所以你在这里,--
已经是在正确的地方了。