我想使用 bash 将一个整数插入到多个子目录中具有各种扩展名的文件名中。
例子:
./trial2/foo.hhh
-->./trial2/foo1.hhh
./trial2/trial3/foo.txt
-->./trial2/trial3/foo1.txt
我试图将文件名与扩展名分开,并在两者之间插入整数:
i=123
find . -type f -exec sh -c ' echo mv "$0" "${0%.*}${i}.${0##*.}" ' {} ;
mv ./trial2/foo.hhh ./trial2/foo.hhh
但不打印可变输出${i}
。为什么?
如果我更改为:
find . -type f -exec sh -c ' mv "$0" "${0%.*}123.${0##*.}" ' {} ;
mv ./trial2/foo.hhh ./trial2/foo123.hhh
数字已打印。 但是,我需要变量${i}
因为它将在包装 for 循环中定义。
Edit
你快到了;你只是碰到了一个引用的微妙之处。i
是在当前 shell 中声明的,因此需要以某种方式传递到由find
运行的sh
中。 在当前命令中,${i}
是单引号,因此在将引用的材料传递给sh
之前,bash
不会对其进行解释。
正如Charles Duffy所建议的那样:
find . -type f -exec sh -c ' echo mv "$0" "${0%.*}${1}.${0##*.}" ' {} "$i" ;
在sh
命令中,$0
是{}
,如您所知。$1
是sh
的第二个参数,"$i"
(i
扩展为单个单词(。sh
命令不是${i}
,而是使用${1}
来访问该参数(i
的副本(。
源语言
在此示例中,i
在当前外壳中进行插值。
Before: find . -type f -exec sh -c ' echo mv "$0" "${0%.*}${i}.${0##*.}" ' {} ;
After: find . -type f -exec sh -c ' echo mv "$0" "${0%.*}'"${i}"'.${0##*.}" ' {} ;
^^ ^^
'"${i}"'
将您从单引号中删除,然后展开i
,然后将您带回单引号。 这样,要传递给sh
的命令将包含所需的i
的值。
在$0
中传递$i
,并在$1
和以后传递您的文件名,您可以从-exec ... {} ;
更改为-exec ... {} +
,因此仅使用一个sh
实例来重命名潜在的多个文件。
以下内容需要 bash,但生成的命令mv
即使存在恶意或令人困惑的文件名(带有空格、换行符、控制字符等(,也能保证正确:
find . -type f -exec bash -c '
logcmd() { printf "%q " "$@"; printf "n"; } # a more accurate replacement for echo
for f; do
logcmd mv "$f" "${f%.*}${0}.${f##*.}"
done' "$i" {} +