Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 检查目录是否包含所有(且仅包含)列出的文件_Bash_Shell_Unit Testing_Filesystems_Sh - Fatal编程技术网

Bash 检查目录是否包含所有(且仅包含)列出的文件

Bash 检查目录是否包含所有(且仅包含)列出的文件,bash,shell,unit-testing,filesystems,sh,Bash,Shell,Unit Testing,Filesystems,Sh,我正在编写单元测试来测试文件IO函数。 在我的目标语言中没有正式的测试框架,所以我的想法是运行一个小测试程序,以某种方式操纵测试目录中的文件,然后在一个小shell脚本中检查结果 为了评估输出,我想检查一个给定的目录是否有所有预期的文件,并且在测试期间没有创建其他文件 我的第一次尝试是这样的: set-e test-e“${test_dir}/a.txt” test-e“${test_dir}/b.txt” test-d“${test_dir}/dir” 查找“${test_dir}”-mind

我正在编写单元测试来测试文件IO函数。 在我的目标语言中没有正式的测试框架,所以我的想法是运行一个小测试程序,以某种方式操纵测试目录中的文件,然后在一个小shell脚本中检查结果

为了评估输出,我想检查一个给定的目录是否有所有预期的文件,并且在测试期间没有创建其他文件

我的第一次尝试是这样的:

set-e
test-e“${test_dir}/a.txt”
test-e“${test_dir}/b.txt”
test-d“${test_dir}/dir”
查找“${test_dir}”-mindepth 1\
-非-wholename“${test_dir}/a.txt”\
-非-wholename“${test_dir}/b.txt”\
-not-全名“${test_dir}/dir”\
|格雷普,退出1 | |正确
这将正确检测
${test_dir}
中是否有两个文件
a.txt
b.txt
,以及一个子目录
dir/
。 如果碰巧有一个文件
c.txt
,测试应该也将失败

然而,这并不能很好地扩展。 有几十个单元测试,每个单元测试都有一组不同的文件/目录,因此我发现自己一次又一次地重复着与上述内容非常相似的内容

因此,我宁愿将上述内容封装为函数调用,如下所示:

if checkdirectory“${test_dir}”a.txt b.txt dir/dir/subdir/dir/.hidden.txt;然后
回音“ok”
其他的
回声“ko”
fi
不幸的是,我不知道如何实现
checkdirectory
(尤其是
find
调用多个
-not-wholename…
节让我头疼)

为了增加一点乐趣,约束条件如下:

  • 同时支持(并区分)文件和目录
  • 必须(从“应”编辑)在Linux、macOS和MSYS2/MinGW上运行,因此:

  • POSIX如果可能的话(实际上它将是
    bash
    ,但可能是bash,我不知道区分文件和目录是什么意思,因为您的上一个
    if
    语句以某种方式是二进制的

    #! /bin/bash
    
    function checkdirectory()
    {
            test_dir="${1}"
            shift
            content="$@"
    
            for file in ${content}
            do
                    [[ -z "${test_dir}/${file}" ]] && return 1
            done
    
            # -I is meant to be appended to "ls" to ignore the files in order to check if other files exist.  
            matched=" -I ${content// / -I } -I ${test_dir}"
    
            [[ -e `ls $matched` ]] && return 1
    
            return 0
    }
    
    
    if checkdirectory /some/directory a.txt b.txt dir; then
            echo "ok"
    else
            echo "ko"
    fi
     
    

    我不知道你上次的
    if
    语句以某种方式是二进制的,你所说的区分文件和目录是什么意思

    #! /bin/bash
    
    function checkdirectory()
    {
            test_dir="${1}"
            shift
            content="$@"
    
            for file in ${content}
            do
                    [[ -z "${test_dir}/${file}" ]] && return 1
            done
    
            # -I is meant to be appended to "ls" to ignore the files in order to check if other files exist.  
            matched=" -I ${content// / -I } -I ${test_dir}"
    
            [[ -e `ls $matched` ]] && return 1
    
            return 0
    }
    
    
    if checkdirectory /some/directory a.txt b.txt dir; then
            echo "ok"
    else
            echo "ko"
    fi
     
    

    一种简单快捷的方法是将
    find
    的输出与参考字符串进行比较:

    让我们从预期的目录和文件结构开始:

    d/FolderA/filexx.csv
    d/FolderA/filexx.doc
    d/FolderA/Sub1
    d/FolderA/Sub2
    
    testassert

    !/usr/bin/env bash
    assertDirContent(){
    
    read-r-d的一种简单快捷的方法是将
    find
    的输出与参考字符串进行比较:

    让我们从预期的目录和文件结构开始:

    d/FolderA/filexx.csv
    d/FolderA/filexx.doc
    d/FolderA/Sub1
    d/FolderA/Sub2
    
    testassert

    !/usr/bin/env bash
    assertDirContent(){
    
    read-r-d's<假设我们有一个目录树作为示例:

    $test_dir/a.txt
    $test_dir/b.txt
    $test_dir/dir/c.txt
    $test_dir/dir/"d e".txt
    $test_dir/dir/subdir/
    
    那么请你试试:

    #!/bin/sh
    
    checkdirectory() {
        local i
        local count
        local testdir=$1
        shift
        for i in "$@"; do
            case "$i" in
                */) [ -d "$testdir/$i" ] || return 1 ;;     # check if the directory exists
                *)  [ -f "$testdir/$i" ] || return 1 ;;     # check if the file exists
            esac
        done
        # convert each filename to just a newline, then count the lines
        count=`find "$testdir" -mindepth 1 -printf "\n" | wc -l`
        [ "$count" -eq "$#" ] || return 1
        return 0
    }
    
    if checkdirectory "$test_dir" a.txt b.txt dir/ dir/c.txt "dir/d e.txt" dir/subdir/; then
        echo "ok"
    else
        echo "ko"
    fi
    

    假设我们有一个目录树作为示例:

    $test_dir/a.txt
    $test_dir/b.txt
    $test_dir/dir/c.txt
    $test_dir/dir/"d e".txt
    $test_dir/dir/subdir/
    
    那么请你试试:

    #!/bin/sh
    
    checkdirectory() {
        local i
        local count
        local testdir=$1
        shift
        for i in "$@"; do
            case "$i" in
                */) [ -d "$testdir/$i" ] || return 1 ;;     # check if the directory exists
                *)  [ -f "$testdir/$i" ] || return 1 ;;     # check if the file exists
            esac
        done
        # convert each filename to just a newline, then count the lines
        count=`find "$testdir" -mindepth 1 -printf "\n" | wc -l`
        [ "$count" -eq "$#" ] || return 1
        return 0
    }
    
    if checkdirectory "$test_dir" a.txt b.txt dir/ dir/c.txt "dir/d e.txt" dir/subdir/; then
        echo "ok"
    else
        echo "ko"
    fi
    

    这是我在晚上想出的一个可能的解决办法

    它会破坏测试数据,因此在许多情况下可能不可用(尽管它可能只适用于单元测试期间动态生成的路径):

    checkdirectory(){
    本地i
    本地testdir=$1
    转移
    #尝试删除所有列出的文件
    因为我在“$@”中是这样做的
    如果[“x${i}”=“x${i%/}”];则
    rm“${testdir}/${i}”返回1
    fi
    完成
    #目录现在应该是空的,
    #因此,请尝试删除列出的目录
    因为我在“$@”中是这样做的
    如果[“x${i}”!=“x${i%/}”];则
    rmdir“${testdir}/${i}”返回1
    fi
    完成
    #最后确保没有留下任何文件
    如果找到“${testdir}”-mindepth 1 | grep.>/dev/null;那么
    返回1
    fi
    返回0
    }
    

    调用
    checkdirectory
    函数时,必须首先调用更深的目录(即
    checkdirectory foo/bar/foo/
    ,而不是
    checkdirectory foo/foo/bar/
    )。

    这是我在晚上想出的一个可能的解决方案

    它会破坏测试数据,因此在许多情况下可能不可用(尽管它可能只适用于单元测试期间动态生成的路径):

    checkdirectory(){
    本地i
    本地testdir=$1
    转移
    #尝试删除所有列出的文件
    因为我在“$@”中是这样做的
    如果[“x${i}”=“x${i%/}”];则
    rm“${testdir}/${i}”返回1
    fi
    完成
    #目录现在应该是空的,
    #因此,请尝试删除列出的目录
    因为我在“$@”中是这样做的
    如果[“x${i}”!=“x${i%/}”];则
    rmdir“${testdir}/${i}”返回1
    fi
    完成
    #最后确保没有留下任何文件
    如果找到“${testdir}”-mindepth 1 | grep.>/dev/null;那么
    返回1
    fi
    返回0
    }
    

    调用
    checkdirectory
    函数时,必须首先调用更深的目录(即
    checkdirectory foo/bar/foo/
    而不是
    checkdirectory foo/foo/bar/
    )。

    jeez.这看起来是个好主意。我确实希望递归地检查(因为测试涉及子目录和目录)为了在文件名中也允许空白,我想我不是使用
    ls-l
    而是使用
    find-exec-echo-found;
    实际上,计算目录中元素数量的正确命令是
    find“${testdir}”-mindepth 1-printf.| wc-c
    感谢您的反馈。一个问题。我们如何在子目录中提供文件名?我可以假设路径名是按照Léa Gris的回答中所述提供的吗?我已经更新了该问题,以便在调用我的wishlist函数时使用子目录中的内容。谢谢您的回答。我已经更新了我的答案根据