如何使用 bash 字符串格式反转日期格式?
How to use bash string formatting to reverse date format?
我有很多文件被命名为:MM-DD-YYYY.pdf
。我想将它们重命名为 YYYY-MM-DD.pdf
我确信有一些 bash 魔法可以做到这一点。这是什么?
来自命令行的直接方法示例:
$ ls
10-01-2018.pdf 11-01-2018.pdf 12-01-2018.pdf
$ ls [0-9]*-[0-9]*-[0-9]*.pdf|sed -r 'p;s/([0-9]{2})-([0-9]{2})-([0-9]{4})/--/'|xargs -n2 mv
$ ls
2018-10-01.pdf 2018-11-01.pdf 2018-12-01.pdf
ls
输出通过管道传输到 sed
,然后我们使用 p 标志打印参数而不修改,换句话说,原始文件的名称,以及 s 来执行和输出转换。
ls
+ sed
结果是一个组合输出,由 old_file_name 和 new_file_name.
最后,我们通过 xargs
管道传输生成的提要以获得文件的有效重命名。
来自 xargs
人:
-n number Execute command using as many standard input arguments as possible, up to number arguments maximum.
您可以使用非常接近 klashxx 之一的以下命令:
for f in *.pdf; do echo "$f"; mv "$f" "$(echo "$f" | sed 's@\(..\)-\(..\)-\(....\)@--@')"; done
之前:
ls *.pdf
12-01-1998.pdf 12-03-2018.pdf
之后:
ls *.pdf
1998-01-12.pdf 2018-03-12.pdf
此外,如果您的文件夹中有其他 pdf
不符合此格式的文件,您可以做的是 select 仅 select 符合以下格式的文件:MM-DD-YYYY.pdf
为此,请使用以下命令:
for f in `find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\{2\}-[0-9]\{2\}-[0-9]\{4\}.pdf' | xargs -n1 basename`; do echo "$f"; mv "$f" "$(echo "$f" | sed 's@\(..\)-\(..\)-\(....\)@--@')"; done
解释:
find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\{2\}-[0-9]\{2\}-[0-9]\{4\}.pdf
此查找命令将仅在当前工作目录中查找符合您语法的文件并提取其基本名称(删除开头的 ./
、文件夹和不考虑具有相同名称的其他类型的文件,其他 *.pdf
文件也将被忽略。
for each file
你做了一个移动,结果文件名是使用 sed 计算的,并向后引用 MM、DD 和 YYYY 的 3 个组
对于当前目录中的文件:
for name in ./??-??-????.pdf; do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done
递归,在当前目录下:
find . -type f -name '??-??-????.pdf' -exec bash -c '
for name do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done' bash {} +
启用 globstar
shell 中的 bash
选项让我们可以执行以下操作(也将像上述解决方案一样处理当前目录中或以下的所有文件):
shopt -s globstar
for name in **/??-??-????.pdf; do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done
这三种解决方案都使用正则表达式来挑选文件名的相关部分,然后将这些部分重新排列成新名称。它们之间的唯一区别是路径名列表的生成方式。
为了安全起见,代码在 mv
前加上 echo
前缀。要实际重命名文件,请删除 echo
(但 运行 至少一次 和 echo
以查看它是否按照您的要求执行)。
对于这些简单的文件名,使用更冗长的模式,您可以稍微简化循环体:
twodigit=[[:digit:]][[:digit:]]
fourdigit="$twodigit$twodigit"
for f in $twodigit-$twodigit-$fourdigit.pdf; do
IFS=- read month day year <<< "${f%.pdf}"
mv "$f" "$year-$month-$day.pdf"
done
这基本上是 ,但没有正则表达式匹配的冗长。
我有很多文件被命名为:MM-DD-YYYY.pdf
。我想将它们重命名为 YYYY-MM-DD.pdf
我确信有一些 bash 魔法可以做到这一点。这是什么?
来自命令行的直接方法示例:
$ ls
10-01-2018.pdf 11-01-2018.pdf 12-01-2018.pdf
$ ls [0-9]*-[0-9]*-[0-9]*.pdf|sed -r 'p;s/([0-9]{2})-([0-9]{2})-([0-9]{4})/--/'|xargs -n2 mv
$ ls
2018-10-01.pdf 2018-11-01.pdf 2018-12-01.pdf
ls
输出通过管道传输到 sed
,然后我们使用 p 标志打印参数而不修改,换句话说,原始文件的名称,以及 s 来执行和输出转换。
ls
+ sed
结果是一个组合输出,由 old_file_name 和 new_file_name.
最后,我们通过 xargs
管道传输生成的提要以获得文件的有效重命名。
来自 xargs
人:
-n number Execute command using as many standard input arguments as possible, up to number arguments maximum.
您可以使用非常接近 klashxx 之一的以下命令:
for f in *.pdf; do echo "$f"; mv "$f" "$(echo "$f" | sed 's@\(..\)-\(..\)-\(....\)@--@')"; done
之前:
ls *.pdf
12-01-1998.pdf 12-03-2018.pdf
之后:
ls *.pdf
1998-01-12.pdf 2018-03-12.pdf
此外,如果您的文件夹中有其他 pdf
不符合此格式的文件,您可以做的是 select 仅 select 符合以下格式的文件:MM-DD-YYYY.pdf
为此,请使用以下命令:
for f in `find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\{2\}-[0-9]\{2\}-[0-9]\{4\}.pdf' | xargs -n1 basename`; do echo "$f"; mv "$f" "$(echo "$f" | sed 's@\(..\)-\(..\)-\(....\)@--@')"; done
解释:
find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\{2\}-[0-9]\{2\}-[0-9]\{4\}.pdf
此查找命令将仅在当前工作目录中查找符合您语法的文件并提取其基本名称(删除开头的./
、文件夹和不考虑具有相同名称的其他类型的文件,其他*.pdf
文件也将被忽略。for each file
你做了一个移动,结果文件名是使用 sed 计算的,并向后引用 MM、DD 和 YYYY 的 3 个组
对于当前目录中的文件:
for name in ./??-??-????.pdf; do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done
递归,在当前目录下:
find . -type f -name '??-??-????.pdf' -exec bash -c '
for name do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done' bash {} +
启用 globstar
shell 中的 bash
选项让我们可以执行以下操作(也将像上述解决方案一样处理当前目录中或以下的所有文件):
shopt -s globstar
for name in **/??-??-????.pdf; do
if [[ "$name" =~ (.*)/([0-9]{2})-([0-9]{2})-([0-9]{4})\.pdf ]]; then
echo mv "$name" "${BASH_REMATCH[1]}/${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]}.pdf"
fi
done
这三种解决方案都使用正则表达式来挑选文件名的相关部分,然后将这些部分重新排列成新名称。它们之间的唯一区别是路径名列表的生成方式。
为了安全起见,代码在 mv
前加上 echo
前缀。要实际重命名文件,请删除 echo
(但 运行 至少一次 和 echo
以查看它是否按照您的要求执行)。
对于这些简单的文件名,使用更冗长的模式,您可以稍微简化循环体:
twodigit=[[:digit:]][[:digit:]]
fourdigit="$twodigit$twodigit"
for f in $twodigit-$twodigit-$fourdigit.pdf; do
IFS=- read month day year <<< "${f%.pdf}"
mv "$f" "$year-$month-$day.pdf"
done
这基本上是