Linux 在bash脚本的sed命令中使用date命令重新格式化日期
我正在尝试将一系列pdf文件从以下文件名重命名: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 "$
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