简体   繁体   English

如何使用bash字符串格式反转日期格式?

[英]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_namenew_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM