重命名多个文件更改扩展名和部分字符串
Rename multiple files changing the extension and part of the string
我在一个目录中有 *.new
个文件的列表。这些文件的名称中包含 D1
,将被替换为 D2
,并且还必须将扩展名从 .new 删除为无
hello_world_D1_122.txt.new -------> hello_world_D2_122.txt
我试过的是
ls -slt | grep -iE "*.new$" | awk -F " " '{print }' | xargs -I {} mv {} "echo {} | sed -e 's/.D1./.D2./g ; s/.new//g'"
此命令没有产生所需的输出。上述命令的输出是
mv: rename hello_world_D1_122.txt.new to echo hello_world_D1_122.txt.new | sed -e 's/D1/D2/g ; s/.new//g': No such file or directory
为什么到处都是使用一堆 shell 工具的方法,您可以为此使用内置的 bash
工具,使用参数扩展语法进行字符串操作
for file in *.new; do
[ -f "$file" ] || continue
temp="${file%*.new}"
mv -- "${file}" "${temp/D1/D2}"
done
"${file%*.new}"
部分从文件名中删除扩展名 .new
,"${temp/D1/D2}"
将 D1
替换为 D2
我不知道为什么坚持使用 GNU xargs
,但您可以使用这种不可读的方式来实现。使用printf
列出以null分隔符的文件并使用xargs -0
以null作为分隔符读取,
printf '%s[=11=]' *.new | xargs -0 -r -I {} sh -c 'temp="${0%*.new}"; mv -- "[=11=]" "${temp/D1/D2}"' {}
除了明显的语法错误外,您当前的尝试还包含大量问题。
参数"echo {} | sed '...'"
是一个文字串; xargs
无法将其解释为命令(尽管它当然会用此字符串中的文件名替换 {}
)。
此外,don't use ls
in scripts,如果你真的需要,使用 ls -l
然后扔掉长格式是......只是愚蠢,而且效率低下,而且容易出错(有关详细信息,请参阅 link。
解决这个问题的明显和更好的方法是不使用 xargs
:
for f in ./*.new; do
[ -f "$f" ] || continue # in case the glob matches no files
d=${f%.new} # trim off extension
mv "$f" "${d/.D1./.D2.}" # replace .D1. with .D2.
done
(我想你想替换文字点,尽管你的正则表达式会匹配除换行符外的任何字符,后跟 D1
后跟除换行符外的任何字符。)
如果您坚持 xargs
解决方案,您可以将上述脚本包装在 bash -c '...'
中并将其传递给 xargs
:
printf '%s[=11=]' ./*.new | xargs -r0 bash -c 'for f; do d=${f%.new}; mv "$f" "${d/.D1./.D2.}"; done' _
使用 GNU Parallel 看起来像这样:
parallel mv {} '{=s/D1/D2/;s/.new//=}' ::: *.new
如果你有疯狂的文件名:
touch "$(printf "Shell Special\n\n'*$!_D1_txt.new")"
parallel -0 mv {} '{=s/D1/D2/;s/.new//=}' ::: *.new
我在一个目录中有 *.new
个文件的列表。这些文件的名称中包含 D1
,将被替换为 D2
,并且还必须将扩展名从 .new 删除为无
hello_world_D1_122.txt.new -------> hello_world_D2_122.txt
我试过的是
ls -slt | grep -iE "*.new$" | awk -F " " '{print }' | xargs -I {} mv {} "echo {} | sed -e 's/.D1./.D2./g ; s/.new//g'"
此命令没有产生所需的输出。上述命令的输出是
mv: rename hello_world_D1_122.txt.new to echo hello_world_D1_122.txt.new | sed -e 's/D1/D2/g ; s/.new//g': No such file or directory
为什么到处都是使用一堆 shell 工具的方法,您可以为此使用内置的 bash
工具,使用参数扩展语法进行字符串操作
for file in *.new; do
[ -f "$file" ] || continue
temp="${file%*.new}"
mv -- "${file}" "${temp/D1/D2}"
done
"${file%*.new}"
部分从文件名中删除扩展名 .new
,"${temp/D1/D2}"
将 D1
替换为 D2
我不知道为什么坚持使用 GNU xargs
,但您可以使用这种不可读的方式来实现。使用printf
列出以null分隔符的文件并使用xargs -0
以null作为分隔符读取,
printf '%s[=11=]' *.new | xargs -0 -r -I {} sh -c 'temp="${0%*.new}"; mv -- "[=11=]" "${temp/D1/D2}"' {}
除了明显的语法错误外,您当前的尝试还包含大量问题。
参数"echo {} | sed '...'"
是一个文字串; xargs
无法将其解释为命令(尽管它当然会用此字符串中的文件名替换 {}
)。
此外,don't use ls
in scripts,如果你真的需要,使用 ls -l
然后扔掉长格式是......只是愚蠢,而且效率低下,而且容易出错(有关详细信息,请参阅 link。
解决这个问题的明显和更好的方法是不使用 xargs
:
for f in ./*.new; do
[ -f "$f" ] || continue # in case the glob matches no files
d=${f%.new} # trim off extension
mv "$f" "${d/.D1./.D2.}" # replace .D1. with .D2.
done
(我想你想替换文字点,尽管你的正则表达式会匹配除换行符外的任何字符,后跟 D1
后跟除换行符外的任何字符。)
如果您坚持 xargs
解决方案,您可以将上述脚本包装在 bash -c '...'
中并将其传递给 xargs
:
printf '%s[=11=]' ./*.new | xargs -r0 bash -c 'for f; do d=${f%.new}; mv "$f" "${d/.D1./.D2.}"; done' _
使用 GNU Parallel 看起来像这样:
parallel mv {} '{=s/D1/D2/;s/.new//=}' ::: *.new
如果你有疯狂的文件名:
touch "$(printf "Shell Special\n\n'*$!_D1_txt.new")"
parallel -0 mv {} '{=s/D1/D2/;s/.new//=}' ::: *.new