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_"{}"' _ {} \;
我也试过 xargs
和 rename
:
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
选项,一旦它显示正确的重命名
我正在尝试为当前目录中所有不是 .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_"{}"' _ {} \;
我也试过 xargs
和 rename
:
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
选项,一旦它显示正确的重命名