Linux 在bash脚本的sed命令中使用date命令重新格式化日期

Linux 在bash脚本的sed命令中使用date命令重新格式化日期,linux,bash,date,sed,Linux,Bash,Date,Sed,我正在尝试将一系列pdf文件从以下文件名重命名:thenewtowncryer-01 Oct 2020.pdf改为2020-10-01\uuuu-\uuunew\u Town\u Cryer.pdf。我已经编写了一个bash脚本,它使用sed来实现这一点,但是我很难弄清楚如何使用date命令将日期从当前的三个字母的月份格式转换过来。这是我迄今为止的脚本行(之前的newname变量是newtowncryer-01 Oct 2020 pdf: newname="$(echo "$

我正在尝试将一系列pdf文件从以下文件名重命名:
thenewtowncryer-01 Oct 2020.pdf
改为
2020-10-01\uuuu-\uuunew\u Town\u Cryer.pdf
。我已经编写了一个bash脚本,它使用
sed
来实现这一点,但是我很难弄清楚如何使用
date
命令将日期从当前的三个字母的月份格式转换过来。这是我迄今为止的脚本行(之前的
newname
变量是
newtowncryer-01 Oct 2020 pdf

newname="$(echo "$newname" | sed -re 's/^(.*) - (.*) ([^ ]+)$/echo "$(date -d "\2" "+%Y-%m-%d")-\1".\3/')"
这一行的输出是
echo“$(日期-d”01 Oct 2020”“+%Y-%m-%d”)-新城Cryer.pdf
,我希望它是
2020-10-01-新城Cryer.pdf

谁能告诉我哪里出错了?谢谢

编辑:这里要澄清的是我到目前为止的整个脚本,因为我的代码片段似乎不清楚。文件名的原始格式是
thenewtowncryer-第1032号[2020年10月1日]。pdf
,我正在尝试将其转换为
2020-10-01\thew New\u-Town\u-Cryer.pdf

#!/bin/bash

find "$1" "*.pdf" -type f -printf "%f\n" | while IFS= read -r f ; do #find all pdfs
  name=$f
  newname="$(echo "$name" | sed -re 's/\./ /g')" # replace .s with spaces to allow 'date'-command to parse the date
  newname="$(echo "$newname" | sed -re 's/\[/!/g')" # replace [s with spaces to allow 'date'-command to parse the date
  newname="$(echo "$newname" | sed -re 's/\]/!/g')" # replace [s with spaces to allow 'date'-command to parse the date
  newname="$(echo "$newname" | sed -re 's/(.*) - (.*) (!.*!)/\1\ - \3/')" # remove issue number
  newname="$(echo "$newname" | sed -re 's/\!//g')" # replace !s with spaces to allow 'date'-command to parse the date
  newname="$(echo "$newname" | sed -re 's/^(.*) - (.*) ([^ ]+)$/echo "$(date -d "\2" "+%Y-%m-%d")-\1".\3/')" # reorder the date and name, split at '-', keep the file extension, prepare for date conversion
  newname="$(echo "$newname" | bash )"
  newname="$(echo "$newname" | sed -re 's/ /./g')" # replace remaining spaces with .
  mv "$name" "$newname"
done

在这里使用bash的原生regex支持,而不是尝试(ab)使用
sed
,可以使代码(可能更长)更清晰易读。 作为一种解决方案,您可以看到在以下位置工作:

这可能适用于您(GNU-sed):


匹配文件名,然后使用
e
标志计算echo命令。

我很难读取该代码。为什么在
sed
替换表达式的右侧有
echo
命令?(为了调用该echo,任何东西如何实际以命令的形式运行sed的输出呢?)请参阅我添加到原始问题中的完整脚本。添加到问题中的代码效率极低,并且存在严重的安全漏洞。命令替换速度慢。外部命令调用速度慢。将生成的代码安全地传输到
bash
非常困难。请不要这样做。好的,谢谢您让我知道现在。我还在学习,所以显然犯了很多错误。我会按照你下面的建议更新我的代码。再次感谢。我真的建议不要使用
e
sed标志,特别是当命令包含扩展到
*
内容的引用时;它是
eval
-等效的,因此很容易使用当一个值意外包含类似shell语法的内容时,会出现安全漏洞……如果您有一个由命令
touch$'Hello-$(rm-rf~).pdf'
创建的输入文件,您就不需要
date-d“$(rm-rf~)”“+%Y-%m-%d”虽然这是一个恶意的例子,但无意中也会发生。@查尔斯达夫同意——用户BeWORKOY,看起来我可以完全更新我的脚本来使用这个BASH的正则表达式支持文件重命名。e> 查找“$1”-名称“*.pdf”-键入f-printf“%f\0”|而IFS=read-r-d”oldname;do…;done
,将此答案中的代码放在
do
done
之间。请注意从
%s\n
更改为
%s\0
——无法将任意文件名列表安全地存储在换行分隔的列表中,因为使用文件名是合法的包含换行符作为其文本的一部分;NUL字符是唯一一个普遍保证不会出现在文件名中的字符。如果您现在遇到了另一个问题,请开始一个新问题。感谢您的建议@Charles Duffy。正如您所看到的,我仍在学习如何执行此操作。唯一的问题是您需要的代码sted基于文件名的格式为
New Town Cryer-01 Oct 2020.pdf
,因为这是我原始问题中输入到行中的格式。但是,该文件名是我脚本中前4个
sed
命令的结果。原始文件名的格式为:
New Town Cr第1032号[2020年10月1日].pdf
。我想从中删除发行号,并将其重命名为以下格式:
2020-10-01\u theu theu New\u Town\u Cryer.pdf
oldname='The New Town Cryer - 01 Oct 2020.pdf'
date_re='(^.*) - ([[:digit:]]{2}) ([[:alpha:]]+) ([[:digit:]]{4})(.*)'
if [[ $oldname =~ $date_re ]]; then
  basename=${BASH_REMATCH[1]}
  day=${BASH_REMATCH[2]}
  month=${BASH_REMATCH[3]}
  year=${BASH_REMATCH[4]}
  ext=${BASH_REMATCH[5]}
  new_date=$(date -d "${day} ${month} ${year}" +%Y-%m-%d)
  newname="${new_date} - ${basename}${ext}"
  echo "Old name: $oldname"
  echo "New name: $newname"
fi
sed -E 's/(.*) - (.*)\.(.*)/echo $(date -d "\2" "+%Y-%m-%d")-\1.\3/e' file