Linux,重命名文件 bash 'no such file or directory' 错误

Linux, rename files with bash 'no such file or directory' error

我正在尝试为当前目录中所有不是 .sh 文件的文件和所有子目录添加前缀,bash 使用 find

问题是我得到一个错误:

mv: cannot move './test.txt' to 'PRE_./test.txt': No such file or directory

我的单线是:

find -type f ! -name "*.sh" -exec sh -c 'mv "{}" PRE_"{}"' _ {} \;

我也试过 xargsrename:

find -type f ! -name "*.sh" -print0 | xargs -0 rename 's/(.*)$/PRE_/'

但是我得到了同样的错误。 怎么了? 提前致谢!

find returns 从 . 一直到文件的路径,所以每个 find 结果都以 ./ 开头,当你开始你的在当前目录中搜索。因此,您的新文件名为 PRE_./test.txt,即位于名为 PRE_. 的目录中的 test.txt。由于没有名为 PRE_. 的目录,mv 无法将 test.txt 移动到该目录中,因此会显示您看到的错误消息。

如果您只重命名当前目录中的文件,而不是子目录中的文件,您可以只使用 bash:

shopt -s extglob 
for f in !(*.sh) ; do [[ -d "$f" ]] || mv "$f" "PRE_$f" ; done

感谢 this answer bash 中的 !(pattern) 构造,在启用 extglob 时可用。它 returns 所有文件名 匹配 pattern.

对于所有子目录中的文件,也使用:

shopt -s extglob globstar
for f in **/!(*.sh) ; do [[ -d "$f" ]] || mv "$f" "${f%/*}/PRE_${f##*/}" ; done

感谢 this answer 的 globstar。 %## 截断路径组件并将 PRE_ 粘贴到文件名开头的正确位置。

Edit 上面两个中的 [[ -d "$f" ]] || 防止循环重命名目录。

如果您不想更改子目录中的文件,您可以使用:

find -type f ! -name "*.sh" -printf "%f\n" | xargs -r rename 's/(.*)$/PRE_/'

问题出在文件名前面的 ./。[=​​11=]

最好不要在 sh -c 的参数中直接使用 {},而是将其值作为参数传递。然后你可以像往常一样使用参数扩展操作来修改它的值。在这里,我们将参数拆分为其目录和文件名组件,然后重新组合它们,包括文件名前缀 PRE_ 以用作 mv.

的参数
script='
d=${1%/*}
f=${1#$d}
mv "" "$d/PRE_$f"
'
find -type f ! -name "*.sh" -exec sh -c "$script" _ {} \;

(这与您最初的尝试只是略有不同;您将 {} 作为参数传递,但没有使用它。相反,您将 "embedding" 值直接传递到传递的字符串中至 sh.)

您还可以使用 -exec + 形式通过传递多个文件名并在 shell 中遍历它们来最大程度地减少对 sh 的调用次数。 (这开始与@cxw 建议的纯 bash 解决方案收敛,但保持 POSIX,以及 bash 3.x,兼容性):

script='
for arg;
 d=${arg%/*}
 f=${arg#$d}
 mv "" "$d/PRE_$f"
done
'
find -type f ! -name "*.sh" -exec sh -c "$script" _ {} +
find -type f ! -name "*.sh" -exec rename -n 's|.*/\K|PRE_|' {} +
  • .*/ 匹配文件名
  • 中的最后一个 /
  • 通过使用 \K 回顾,我们可以避免在这种情况下需要捕获组

rename 中删除 -n 选项,一旦它显示正确的重命名