是否对xargs使用bash类型`${i%.mp3}`语法?

是否对xargs使用bash类型`${i%.mp3}`语法?,bash,syntax,xargs,Bash,Syntax,Xargs,用法示例(人为!):将.mp3文件重命名为.txt 我希望能做一些类似的事情 find -name '*.mp3' -print0 | xargs -0 -I'file' mv file ${file%.mp3}.txt 这不起作用,所以我求助于管道通过sed-e的/.mp3//g'查找的输出,这就达到了目的 看起来有点老土有没有一种方法可以使用常用的bash${x%y}语法? find . -type f -name '*.mp3' | while read -r F do mv "$F

用法示例(人为!):将.mp3文件重命名为.txt

我希望能做一些类似的事情

find -name '*.mp3' -print0 | xargs -0 -I'file' mv file ${file%.mp3}.txt
这不起作用,所以我求助于管道
通过
sed-e的/.mp3//g'
查找
的输出,这就达到了目的

看起来有点老土有没有一种方法可以使用常用的bash
${x%y}
语法?

find . -type f -name '*.mp3' | while read -r F
do
  mv "$F" "${F%.mp3}.txt"
done
Bash 4+

shopt -s globstar
shopt -s nullglob
for file in **/*.mp3
do
    mv "$file" "${file%.mp3}.txt"
done

否,
xargs-0-I'file'mv file${file%.mp3}.txt
将不起作用,因为
file
变量将由xargs程序而不是shell展开。实际上,将其称为变量并不十分正确,在xargs手册中称为“replace str”

更新:为了只使用xargs和bash(没有sed或类似的),您当然可以让xargs启动bash进程,然后它可以执行您想要的任何替换:

find -name '*.mp3' -print0 | xargs -0 bash -c \
'while [ -n "$1" ]; do mv "$1" "${1%.mp3}.txt" ; shift; done;' "bash"

如果已安装GNU并行:

find -name '*.mp3' -print0 | parallel -0 mv {} {.}.txt
如果您的文件名不包含\n(换行符),这也会起作用:

find -name '*.mp3' | parallel mv {} {.}.txt

观看介绍视频,了解更多关于GNU Parallel的信息,只是为了添加另一个建议,尽管它没有使用shell的替代机制,而是使用sed

find -name '*.mp3' -print |
sed -e 's/\.mp3$//' -e "s/.*/mv '&\.mp3' '&\.txt'/" |
sh
换句话说,为每个文件名创建一个
mv
命令行,并将结果传递给
sh

如果任何文件的文件名中有撇号(单引号),则此操作将失败。我发表这篇文章主要是为了反驳“如果你只有xargs,那么每个问题看起来都像钉子”综合症

并非所有SED都具有完全相同的语法。特别是,我不能100%确定在一些粗糙的旧SunOS上可以有多个-e参数(在类似
/usr/ucb/blah/barf/vomit/xpg4/bin/sed的东西中查找与XPG兼容的sed


我知道怎么做;这个问题的目的是看看是否有可能用xargs实现这一点,并且不让它立即展开replace str(我猜)。有没有办法让shell在xargs完成它的工作之前展开表达式?bash的原因是它被解释为$0,所以$1变成了xargs输入的内容。你问了一个问题,没有一个纯粹的答案。或者至少是一个你愿意接受的答案,因为你从来没有选择接受。我的“黑客”方式是管道
find…|塞德…|xargs…
。这是你说的另一种方法。因此,为了清楚地分解它,
xargs
本身不支持Bash变量扩展。你能用很多不同的方法解决这个问题吗??正如你已经知道的,是的!您可以在
xargs
中“纯粹”执行此操作吗?不当然是当代狂欢节。但是它不能移植回真正的老Bash版本,这里的OP可能会遇到这种情况,所以我尝试让它合理地可移植。即使是在“传家宝”
sh
和其他类似的累赘外壳中,这也应该起作用。
perl rename.pl 's/\.mp3$/.txt/' *.mp3  
# Or **/*.mp3 for zsh and bash with specific settings set, for a recursive 
# rename.