重命名多个文件,更改扩展名和字符串的一部分

问题描述 投票:2回答:3

我在目录中有*.new文件列表。这些文件在其名称中包含D1,将被替换为D2,并且还必须从.new删​​除扩展名为no

hello_world_D1_122.txt.new -------> hello_world_D2_122.txt

我尝试的是

ls -slt | grep -iE "*.new$" | awk -F " " '{print $10}' | 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
bash shell xargs
3个回答
1
投票

除了明显的语法错误之外,您当前的尝试还包含大量问题。

参数"echo {} | sed '...'"是一个文字字符串; xargs无法将此解释为命令(尽管它当然会将{}替换为此字符串中的文件名)。

另外,don't use ls in scripts,如果你真的不得不,使用ls -l,然后丢弃长格式......只是愚蠢,低效,容易出错(详见链接)。

解决这个问题的明显而优越的方法是没有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\0' ./*.new | xargs -r0 bash -c 'for f; do d=${f%.new}; mv "$f" "${d/.D1./.D2.}"; done' _

4
投票

为什么所有关于使用一堆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\0' *.new | xargs -0 -r -I {} sh -c 'temp="${0%*.new}"; mv -- "${0}" "${temp/D1/D2}"' {}

1
投票

使用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
© www.soinside.com 2019 - 2024. All rights reserved.