Bash:同时使用“if”和“find”来检查文件夹中的文件

Bash:同时使用“if”和“find”来检查文件夹中的文件

我有一个父文件夹,其中包含一系列“histogram_0000_0000”文件夹。我正在尝试制作一个 bash 脚本,在每个文件夹中搜索文件“out.txt”,并在每次在文件夹中找到该文件时返回(以检查该文件是否存在于所有文件夹中)。我得到的脚本是;

#!/bin/bash
joblist='job_list.txt'
njobs=`wc ${joblist} | awk '{print $1}'`

cwd=`pwd`
for ((i=1 ; i <= ${njobs} ; i++ )); do
        folder=`awk '(NR=='${i}'){print}' ${joblist}`
        echo $folder
        cd ${folder}
        if [ find -name "out.txt" ]
        then
                echo out.txt found in $folder
        fi
        cd ${cwd}
done

但每次运行时都会出现错误;

./checkrun.sh: 第 10 行: [: -name: 需要二元运算符

我环顾四周,尝试使用“[[”和“]]”,但仍然不知道为什么我有运气!任何帮助都会很棒。谢谢,-杰克

答案1

[...]测试字符串或数字表达式。如果您想查看find命令是否匹配,您需要测试它是否提供了任何输出(非空字符串,使用 进行测试-n)。

if [[ -n "$(find -name 'out.txt')" ]]
then
    echo "out.txt found in $folder"
fi

请注意,我使用现代$(...)语法来捕获命令的输出,而不是已弃用的反引号`...`

其他的建议,

  • 您可以简化njobs=wc ${joblist} | awk '{print $1}'`` 用于njobs=$(wc -l <"$joblist")获取行数。

  • $i作为awk变量传入,folder=$(awk -v i="$i" 'NR==i {print}' "$joblist}")

  • 不要cd进入子文件夹,然后依靠使用cd返回到原来的位置。使用相对路径引用子目录或使用子 shell 将其保留cd在有限的上下文中。这里我使用第一种方法

      echo "$folder"
      if [[ -n "$(find "$folder" -name 'out.txt')" ]]
      then
          echo "out.txt found in $folder"
      fi
    
  • 如果$folder始终是相对路径,则在用作路径的任何地方都将其引用为“./$folder”。这可以防止它以破折号 ( -) 开头,这可能会混淆可能尝试将其解释为一系列选项的命令。

  • shellbash已经有一个当前工作目录的变量,因此您可以简化cwd=`pwd`cwd="$PWD"

  • 使用https://shellcheck.net/检查您的代码。 (如果您担心共享私有代码,则可以在本地安装它。)

答案2

#!/bin/bash
joblist='job_list.txt'
njobs=`wc ${joblist} | awk '{print $1}'`

cwd=`pwd`
while IFS= read -r line
do
        folder="$line"   #`awk '(NR=='${i}'){print}' ${joblist}`
        echo $folder
        cd ${folder}
        if [ -f out.txt ]
        then
                echo out.txt found in $folder
        fi
        cd ${cwd}
done < job_list.txt

我希望这有帮助。更容易一点......line=current-line-from'job_list.txt' 它逐行读取,所以文件看起来像这样:

folder1
folder2
folder234

我的输出:

france1@macubuntu:/tmp/tmdf$ bash script.sh 
folder1
folder2
folder234
out.txt found in folder234
france1@macubuntu:/tmp/tmdf$ 

希望我有帮助...

答案3

我会用zsh它来代替bash

#! /bin/zsh -
joblist='job_list.txt'
dirs=( ${(f)"$(<$joblist)"} )

for dir in $dirs; do
  first_out=( $dir/**/out.txt(NDY1) )
  if (( $#first_out )); then
    print -r out.txt found in $dir
  fi
done

对于bash其他 GNU find,等价物是:

#! /bin/bash -
joblist='job_list.txt'

dirs=(); readarray -t dirs < "$joblist"

for dir in "${dirs[@]}"; do
  [[ -n $dir ]] || continue
  [[ $dir = [/.]* ]] || dir=./$dir

  first_out=$(find "$dir" -name out.txt -print -quit)

  if [[ -n $first_out ]]; then
    printf '%s\n' "out.txt found in $dir"
  fi
done

一些注意事项:

  • readarray -t lines < file可以将文件的行存储到数组中,但请注意,如果file无法打开,readarray甚至不会运行,因此$dirs不会被设置,因此预先初始化变量很重要。
  • bash最终添加了对 zsh 风格的递归通配符 ( **/) 选项的支持globstar。然而,在符号链接处理方面它仍然有些问题(行为随版本而变化),而且更重要的是在这种情况下,它仍然没有添加对 glob 限定符的支持,例如 for NnullglobforDdotglob停止Y1在第一个匹配甚至不用对上面使用的列表进行排序。
  • findfind "$dir"如果$dir以 开始,则会闯入-。虽然find确实支持--标记选项的结尾,但这在这里没有帮助,因为-如果不是选项,则以 开头的参数仍将被视为谓词(如(, )or !)。这就是为什么我们在前面加上./不是$dir绝对的并且尚未以 开头的 s .(因此-my-annoying-dir-变为./-my-annoying-dir-)。 BSDfind支持find -f "$dir"避免该问题,但 GNU 尚不支持find
  • 如果您只想检查至少一个是否存在out.txt,则没有必要找到所有这些。您可以在第一场比赛时停止。因此(GNU 特定的)-quit(一些 BSD-exit对此有规定)。
  • zsh${(f)"$(<file)"}在换行符上进行分割,但是当不加引号时,会删除空元素(如果没有,$dirs下面的下一个不加引号的元素将删除它们)。空路径通常不是有效路径,因此应该会产生错误,但是当与 串联时/something,它们会令人烦恼地变成不相关的可能有效的绝对路径。当前面加上./成为当前目录时。所以最好在这里跳过它们,因此[[ -n $dir ]] || continue在 bash 变体中。

相关内容