[英]How to use bash string formatting to reverse date format?
I have a lot of files that are named as: MM-DD-YYYY.pdf
. 我有很多文件名为:
MM-DD-YYYY.pdf
。 I want to rename them as YYYY-MM-DD.pdf
I'm sure there is some bash magic to do this. 我想将它们重命名为
YYYY-MM-DD.pdf
我敢肯定有一些bash魔术可以做到这一点。 What is it? 它是什么?
For files in the current directory: 对于当前目录中的文件:
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
Recursively, in or under the current directory: 在当前目录中或其下递归地:
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 {} +
Enabling the globstar
shell option in bash
lets us do the following (will also, like the above solution, handle all files in or below the current directory): 在
bash
启用globstar
shell选项,我们可以执行以下操作(也将像上述解决方案一样,处理当前目录中或当前目录下的所有文件):
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
All three of these solutions uses a regular expression to pick out the relevant parts of the filenames, and then rearranges these parts into the new name. 这三种解决方案均使用正则表达式来选择文件名的相关部分,然后将这些部分重新排列为新名称。 The only difference between them is how the list of pathnames is generated.
它们之间的唯一区别是路径名列表的生成方式。
The code prefixes mv
with echo
for safety. 为了安全起见,该代码在
mv
加上echo
。 To actually rename files, remove the echo
(but run at least once with echo
to see that it does what you want). 要实际重命名文件,请删除
echo
(但至少应使用 echo
运行一次,以查看其是否可以满足您的要求)。
A direct approach example from the command line: 命令行中的直接方法示例:
$ 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})/\3-\1-\2/'|xargs -n2 mv
$ ls
2018-10-01.pdf 2018-11-01.pdf 2018-12-01.pdf
The ls
output is piped to sed
, then we use the p flag to print the argument without modifications, in other words, the original name of the file, and s to perform and output the conversion. ls
输出通过管道传递给sed
,然后我们使用p标志来打印参数而无需修改,换句话说,使用文件的原始名称,然后使用s执行并输出转换。
The ls
+ sed
result is a combined output that consist of a sequence of old_file_name and new_file_name . ls
+ sed
结果是一个组合输出,由一个old_file_name和new_file_name序列组成。
Finally we pipe the resulting feed through xargs
to get the effective rename of the files. 最后,我们通过
xargs
传递结果提要,以有效地重命名文件。
From xargs
man : 来自
xargs
man :
-n number Execute command using as many standard input arguments as possible, up to number arguments maximum.
-n number使用尽可能多的标准输入参数执行命令,最大数量为数字。
You can use the following command very close to the one of klashxx : 您可以非常接近klashxx之一使用以下命令:
for f in *.pdf; do echo "$f"; mv "$f" "$(echo "$f" | sed 's@\(..\)-\(..\)-\(....\)@\3-\2-\1@')"; done
before: 之前:
ls *.pdf
12-01-1998.pdf 12-03-2018.pdf
after: 后:
ls *.pdf
1998-01-12.pdf 2018-03-12.pdf
Also if you have other pdf
files that does not respect this format in your folder, what you can do is to select only the files that respect the format: MM-DD-YYYY.pdf
to do so use the following command: 另外,如果您的文件夹中还有其他不遵守此格式的
pdf
文件,您可以执行的操作是仅选择遵守该格式的文件: 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@\(..\)-\(..\)-\(....\)@\3-\2-\1@')"; done
Explanations: 说明:
find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\\{2\\}-[0-9]\\{2\\}-[0-9]\\{4\\}.pdf
find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\\{2\\}-[0-9]\\{2\\}-[0-9]\\{4\\}.pdf
this find command will look only for files in the current working directory that respect your syntax and extract their basename (remove the ./
at the beginning, folders and other type of files that would have the same name are not taken into account, other *.pdf
files are also ignored. find . -maxdepth 1 -type f -regextype sed -regex './[0-9]\\{2\\}-[0-9]\\{2\\}-[0-9]\\{4\\}.pdf
此查找该命令将仅在当前工作目录中查找符合您的语法并提取其基名的文件(删除./
开头,不考虑具有相同名称的文件夹和其他类型的文件,其他*.pdf
文件也将被忽略。
for each file
you do a move and the resulting file name is computed using sed and back reference to the 3 groups for MM,DD and YYYY for each file
您进行移动,然后使用sed并向后引用MM,DD和YYYY的3组,从而计算出文件名
For these simple filenames, using a more verbose pattern, you can simplify the body of the loop a bit: 对于这些简单的文件名,使用更详细的模式,可以稍微简化循环的主体:
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
This is basically @Kusalananda's answer , but without the verbosity of regular-expression matching. 这基本上是@Kusalananda的答案 ,但是没有正则表达式匹配的冗长。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.