mv: cannot stat shell 脚本中没有这样的文件或目录

mis*_*yes 25 shell rename

我写了一个脚本将一些文件从一个文件夹移动到另一个文件夹,但出现以下错误,我检查了 2 个文件夹并注意到 1 个文件夹有这样的文件,另一个没有这样的文件,但为什么它们都显示“mv无法统计没有这样的文件或目录”

mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/data/*': No such file or directory
mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.42.17.124_tcp.folder/data/*': No such file or directory
mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/195.113.161.13_tcp.folder/data/*': No such file or directory
mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/*': No such file or directory
mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.199.61.205_tcp.folder/data/*': No such file or directory
mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.51.218.235_tcp.folder/data/*': No such file or directory
mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/213.73.40.105_tcp.folder/data/*': No such file or directory
mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/41.225.7.4_tcp.folder/data/*': No such file or directory
mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/83.230.127.122_tcp.folder/data/*': No such file or directory
[esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/
[esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/
129.88.70.226   132.187.230.1    138.96.116.22   155.185.54.250   192.38.109.144  193.136.227.163  193.175.135.61  195.113.161.13  83.230.127.122
130.104.72.200  132.227.62.122   147.83.29.232   156.17.10.52     192.42.43.22    193.137.173.218  193.205.215.74  212.199.61.205
131.130.69.164  132.252.152.194  148.81.140.193  157.181.175.249  192.43.193.71   193.144.21.131   193.226.19.30   212.51.218.235
131.188.44.102  134.151.255.180  152.66.245.162  160.78.253.31    193.1.170.136   193.145.46.243   194.199.68.165  213.73.40.105
131.254.208.10  138.48.3.203     152.81.47.4     192.114.4.3      193.136.166.56  193.166.160.98   194.42.17.124   41.225.7.4
Run Code Online (Sandbox Code Playgroud)

脚本是:

list=`ls dest_folder`
cd dest_folder
cwd=`pwd`
for folder in $list;do
        mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}
done
Run Code Online (Sandbox Code Playgroud)

我跑了进去/home/esolve/project/capture/tcp_50x50/

Mat*_*Mat 37

mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}
Run Code Online (Sandbox Code Playgroud)

'那里的引号 ( ) 可以防止 shell 进行通配。将*被逐字传递给mv命令,因为它没有找到文件名为从而未能*在指定的目录中。

将此更改为:

mv "${cwd}/${folder}/data"/* "${cwd}/${folder}"
Run Code Online (Sandbox Code Playgroud)

(如果您的目录名称中包含空格,请使用双引号来防止出现问题。*在引号之外。)

但是,您仍然会收到空目录的错误。(同样的原因:如果文件没有找到模式的匹配项,它会将模式本身作为参数传递给命令。)


Sté*_*las 10

您的代码有几个问题:

list=`ls dest_folder`
Run Code Online (Sandbox Code Playgroud)

您将ls没有尾随换行符的输出存储到$list. ls输出以换行符分隔的文件名列表。newline与文件名中的任何字符一样有效,因此无法可靠地使用输出。例如ls,包含一个目录的输出ab包含一个名为a<newline>b.

 cd dest_folder
Run Code Online (Sandbox Code Playgroud)

您没有检查该命令是否失败。通常,您应该检查命令的退出状态,但对于 来说尤其如此cd,因为其余命令假定您在该新目录中,如果您不在该目录中,则可能会产生严重后果。

cwd=`pwd`
Run Code Online (Sandbox Code Playgroud)

POSIX shell 已经在$PWD变量中维护了当前目录的(一个)路径,因此您不需要在pwd此处使用(特别是在一般情况下,因为命令替换会从路径中删除尾随换行符)。此外,mv接受相对路径,因此您无需建立绝对路径。

for folder in $list;do
Run Code Online (Sandbox Code Playgroud)

不加引号的变量是shell 中的split+glob运算符。也就是说,变量的内容被拆分(在 中提到的分隔符上$IFS,空格的特殊规则),并且该拆分产生的每个元素都会查找通配符,以便它们可以扩展到匹配文件的列表。

在这里,您确实需要拆分,但仅适用于换行符,并且您不想要通配符,因此您需要禁用它:

 IFS='
 '; set -f
 for folder in $list
Run Code Online (Sandbox Code Playgroud)
   mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}
Run Code Online (Sandbox Code Playgroud)

同样,不加引号的变量是split+glob运算符。在这里,您既不需要,因此需要引用这些变量。

如前所述,通配符仅在未引用时扩展,因此您需要将其*从引号中移出。如果您之前使用 禁用了通配set -f,则需要set +f在调用该命令之前将其恢复。

更好的写法是:

cd dest_folder &&
  for folder in */;do
    mv -- "${folder}data/"* "$folder"
  done
Run Code Online (Sandbox Code Playgroud)

不过有几点说明:

  • 这将排除隐藏文件夹,并且不会从data文件夹中移动隐藏文件。
  • 我们不会检查在此过程中是否被覆盖的文件(您可能希望将-i选项添加到mv)。
  • 通过使用*/,我们只循环遍历目录,但这也包括指向目录的符号链接。如果您不愿意,则需要[ -L "${folder%/}" ] && continue在循环内添加一个。
  • 如果那里没有非隐藏文件夹*/将扩展到自身,因此您将收到错误消息,mv说它找不到名为*/data/*. 同样,如果任何文件夹中都没有非隐藏文件,您将收到一条that-folder/data/*不存在的错误消息。