我有很多文件,其中文件名包含文件创建日期 ( IMG_YYYYMMDD_hhmmss.jpg
):
IMG_20171015_133516.jpg
IMG_20171015_133827.jpg
IMG_20171015_142634.jpg
IMG_20171015_142834.jpg
IMG_20171015_142857.jpg
但实际文件创建日期不同。我需要将其设置回文件名的日期。
我知道如何将所有文件的日期更改为当前日期:
find -type f -exec touch {} \;
以及如何解析文件名以获得正确格式的日期touch -t
echo IMG_20171015_133516.jpg | awk -F_ '{print $2 substr($3,0,4) "." substr($3,5,2)}'
201710151335.16
但我不知道如何将这些命令组合在一起来更改所有文件。
find -type f -exec touch -t"$(echo '{}' | awk -F_ '{print $2 substr($3,0,4) "." substr($3,5,2)}')" {} \;
回报
touch:无效的日期格式“.”
答案1
在外壳中:
for f in ./IMG_*.jpg ; do
t=${f##*/}
touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}"
done
Bash、ksh、zsh 等都有${var:n:m}
子字符串扩展,如果您需要递归地执行它,请启用globstar
并使用**/IMG_*.jpg
。
这样做find
也需要 shell:
$ find -name "IMG_*.jpg" -exec bash -c '
for f; do t=${f##*/}; touch "$f" -t "${t:4:8}${t:13:4}.${t:17:2}" ; done
' sh {} \+
脚本后 Bash 的第一个参数指向变量$0
,该变量通常包含 shell 名称。其余的转到位置参数$1
、$2
等和for f
/或for f in "$@"
循环它们。这里的构造相当常见(至少在 unix.SE 答案中)。这里循环的主要部分与第一个示例中的相同。
find
您问题中的命令不起作用find .. -exec touch -t"$(...)" {} \;
,因为命令替换用双引号引起来,因此它在find
运行之前会扩展。字面上{}
通过管道传送到awk
,而碰巧awk
脚本只打印一个点。
如果您确实将命令替换放入单身的引号,它将按touch
原样传递(find
只会替换{}
)。touch
会得到参数-t$(echo ...)
、美元符号、括号等等。find
本身并不通过 shell 运行命令,我们需要显式地执行它,如上所述。
以单引号为例:
$ find -name x -exec echo 'hello $(foo {})' \;
hello $(foo ./x)