如何使用Bash使用“find”更改类型文件的扩展名?

时间:2016-09-10 02:34:59

标签: linux bash shell unix scripting

用户输入他们正在寻找的文件类型;它存储在$arg1;他们想要更改它们的文件类型存储为$arg2。我能够找到我正在寻找的东西,但我不确定如何保持文件名相同但只是将类型...即{,file1.txt更改为file1.log

find . -type f  -iname "*.$arg1" -exec mv {} \;

4 个答案:

答案 0 :(得分:2)

我会这样做:

find . -type f  -iname "*.$arg1" -print0 |\
    while IFS= read -r -d '' file; do
        mv -- "$file" "${file%$arg1}$arg2"
    done

我接受了find命令并将其输出提供给while循环。在该循环中,我正在进行实际的重命名。这样我将文件的名称作为变量,我可以使用bash的字符串操作操作来操作。

答案 1 :(得分:2)

要启用shell parameter expansions的全部功能,您可以在bash -c操作中致电exec

find . -type f -iname "*.$arg1" -exec bash -c 'echo mv "$0"  "${0%.*}.$1"' {} "$arg2" \;

我们将{}"$arg2"作为参数添加到bash -c,以便在命令中可以$0$1访问它们。 ${0%.*}删除扩展名,替换为$arg2展开为的任何内容。

实际上,该命令只打印它将执行的mv命令;要实际重命名文件,必须删除echo

引用是相关的:bash -c的参数是单引号,以防止$0$1过早扩展,以及mv的两个参数,以及引用arg2来处理文件名中包含空格。

答案 2 :(得分:2)

find -exec bash提示与bash循环提示相结合,您可以使用+上的-exec终结符告诉find将多个文件名传递给单个调用bash命令。将新类型作为第一个参数传递 - 它显示在$0中,因此通过for循环方便地跳过其余​​的命令行参数 - 并且您有一个非常有效的解决方案:< / p>

find . -type f -iname "*.$arg1" -exec bash -c \
  'for arg; do mv "$arg" "${arg%.*}.$0"; done' "$arg2" {} +

或者,如果您有Linux rename命令的任一版本,则可以使用它。默认安装在Ubuntu和其他基于Debian的发行版上的Perl one(a.k.a。prename;也可以通过brew install rename从Homebrew通过OS X获得),如下所示:

find . -type f -iname "*.$arg1" -exec rename 's/\Q'"$arg1"'\E$/'"$arg2"'/' {} +

这看起来有点难看,但它实际上只是许多UNIX工具所熟悉的s/old/new/替换命令。围绕\Q的{​​{1}}和\E会将后缀中的任何奇怪字符都解释为可能与意外事件匹配的正则表达式元字符; $arg1之后的$确保模式仅在文件名末尾匹配。

默认安装在基于Red Hat的Linux发行版(Fedora,CentOS等)上的基于模式的版本更简单:

\E

但它也很笨:如果你find . -type f -iname "*.$arg1" -exec rename ".$arg1" ".$arg2" {} + ,你会得到一个名为rename .com .exe stackoverflow.com_scanner.com的文件。

答案 3 :(得分:1)

如果你有perl rename命令

示例目录:

$ find
.
./a"bn.txt
./t2.abc
./abc
./abc/t1.txt
./abc/list.txt
./a bc.txt

示例args:

$ arg1='txt'
$ arg2='log'

干运行:

$ find -type f -iname "*.$arg1" -exec rename -n "s/$arg1$/$arg2/" {} +
rename(./a"bn.txt, ./a"bn.log)
rename(./abc/t1.txt, ./abc/t1.log)
rename(./abc/list.txt, ./abc/list.log)
rename(./a bc.txt, ./a bc.log)

一旦可以,请删除-n选项:

$ find -type f -iname "*.$arg1" -exec rename "s/$arg1$/$arg2/" {} +
$ find
.
./a bc.log
./t2.abc
./abc
./abc/list.log
./abc/t1.log
./a"bn.log