【问题标题】:unable to process files of a directory in for loop in linux无法在linux的for循环中处理目录的文件
【发布时间】:2011-09-11 08:52:48
【问题描述】:

我的目录有 2 个子目录,并且子目录也很少,而且它们有一些文件。我需要重命名所有文件以将 html 扩展名附加到文件名。 目录结构是这样的

main-directory
   sub-directory
   sub-directory
       sub-directory
          file1
          file2
          and so on to lot of files

现在我不能使用这样的东西

for file in main-directory/*
do
if [ -f "$file" ]
then `mv "$file" "$file.html"`
fi
done

因为 for 循环不会递归地使用路径。所以我用了这样的东西

for file in `ls -1R main-directory`  // -1 for showing file and directory names separated by new lines and -R for recursive travel
do
if [ -f "$file" ]
then `mv "$file" "$file.html"`
fi
done

以上代码无法重命名文件。检查是否行

for file in `ls -1R main-directory`  

正在工作,我写了这样的东西

for file in `ls -1R main-directory`
do
if [ -f "$file" ]
echo $file
done

这不显示任何内容。有什么问题?

【问题讨论】:

    标签: linux bash for-loop directory file-rename


    【解决方案1】:

    您可以使用 find 和 look into of type file 然后 -exec 来更改所有文件,然后附加 .html。

    find main-directory -type f -exec mv -v '{}' '{}'.html \; 
    

    【讨论】:

    • @Jasonw:上面的 for 循环有什么问题?你能解释一下你的命令吗? {} 做了什么,为什么 \ 到底是什么?
    • @lovesh,首先,你的 if 循环哈希语法错误。其次, ls 只列出目录的内容,然后 if 检查验证文件是否存在。对于您的实现,在文件不存在之前不会显示该文件。在if检查之前,尝试做一个echo $file然后做一个pwd,你就会明白了。
    • @Jasonw:我在 for 循环中 do 之后放了一个 echo $file,我得到了一个主目录的名称和目录列表,每个都在一个新行上
    • @lovesh,这是我的版本,如果您注意到 $cur_dir 和 $file,$cur_dir 将始终输出您执行此脚本的位置。那么 $file 是文件名而不是绝对路径。所以当你检查 if [ -f "$file" ] ; bash 找不到该文件。 #!/bin/sh 用于ls -R main-directory 中的文件; do cur_dir=pwd echo "where $cur_dir file $file" if [ -f "$file" ];然后 echo $file fi 完成
    • @Jasonw:: 是的,我知道了,我需要在文件前面附加当前目录名称
    【解决方案2】:

    在您的第一个 for 循环中,mv 命令不应使用反引号。

    在您的第二个for 循环中,if 语句的语法不正确。没有thenfi。应该是:

    for file in `ls -1R main-directory`
    do
    if [ -f "$file" ]
    then
       echo $file
    fi
    done
    

    但即便如此,这也行不通,因为ls -1R main-directory 只为您提供文件名,而不是文件的绝对路径。将你的回声移到 if 语句之外进行测试:

    for file in `ls -1R main-directory`
    do
       echo $file
    done
    

    因此ls -1R main-directory 不是获取当前目录中所有文件的好方法。请改用find . -type f

    【讨论】:

    • 为什么不在第一个 for 循环中为 mv 反引号。是的,我忘了在这篇文章中输入thenfidone,但我的代码中有这个
    【解决方案3】:

    出于某种原因,我永远记不起find ... -exec 语法与{}\;。相反,我养成了只使用 find 提供的循环的习惯:

    find main-directory -type f | while read file
    do
        mv "$file" "$file.html"
    done
    

    find 将每个文件输出到标准输出,read file 将一次使用一行并将该行的内容设置为 $file 环境变量。然后你可以在循环体的任何地方使用它。

    我使用这种方法来解决很多像这样的小问题,我需要遍历一堆输出并做一些有用的事情。因为它更通用,所以我使用它比深奥的find ... -exec {} \; 方法更多。

    另一个技巧是在您的命令前面加上echo,以便在对您的系统造成潜在损害之前进行快速的健全性检查:

    find find main-directory -type f | while read file
    do
        echo mv "$file" "$file.html"
    done
    

    【讨论】:

      【解决方案4】:

      这是我的问题的答案。人们用 1 衬里做出回应,这是一种巧妙的方法,但我没有从这 1 衬里中得到太多,所以这是我想要的东西

      IFS=$'\n'   // this is for setting field separator to new line because the default is whitespace
      dir=main-directory
      for file in `ls -1R main-directory | sed 's/:$//'`  // -1 for showing file and directory names separated by new lines and -R for recursive travel
      do
      if [ -f "$dir/$file" ]
      then `mv "$dir/$file" "$dir/$file.html"`
      elif [ -d "$file" ]
      then dir=$file
      fi
      done
      

      这里sed 's/:$//' 在行尾检测到: 并将其删除。这是阻止我的代码运行的原因之一,因为每当ls -1R main-directory 检测到一个目录时,它都会在末尾附加一个:

      【讨论】:

      • 答案是一行,因为没有理由让它超过一行。我会花一些时间来理解使用find 命令而不是ls 提供的答案。使用find,您可以避免上述问题,您必须从目录名称中删除:,并跟踪dir 变量。此外,您没有发现的一个问题是处理文件名或目录中的空格。
      • @Steve Prentice:我已经承认其他答案更好,但我想看看是否有办法用 for 循环做到这一点,是的,我意识到我没有处理对于文件名中的spaces,所以我将field separator 更改为换行符
      猜你喜欢
      • 2015-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多