使用通配符批量复制略有不同的名称

使用通配符批量复制略有不同的名称

我想复制单个目录中的多个文件。示例文件名以 开头error042021.mysite,我希望新名称以 结尾-dev.co.at.txt。我认为我需要数字通配符,因为数字会有所不同:022021032021042021等。(数字=月份、年份)。

例如这就是我想要做的事情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 …:)。

  • FILE不是一个好的变量名。如果你习惯了大写名称,那么迟早你会覆盖你的PATH。在脚本中使用名称一般采用小写形式file,,(fpathzsh虽然不在)、……

  • 在解析时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/shshebang 是因为代码是完全可移植的。
  • 我在生成路径名时使用了绝对路径,因此不需要--在调用 时cp。我仍然决定把它放在那里以促进良好的做法。即使你选择cd /…/error首先和for f in error??????.mysite.at.txt; do …,那么扩展的字符串$f永远不会以 开头-,并且 的存在--不会改变任何东西。但如果有人拿走这段代码并将其与类似模式一起使用,??????.mysite.at.txt那么他们可能真的需要--。所以你在这里,--已经是在正确的地方了。

相关内容