Bash 检查目录是否包含所有(且仅包含)列出的文件
我正在编写单元测试来测试文件IO函数。 在我的目标语言中没有正式的测试框架,所以我的想法是运行一个小测试程序,以某种方式操纵测试目录中的文件,然后在一个小shell脚本中检查结果 为了评估输出,我想检查一个给定的目录是否有所有预期的文件,并且在测试期间没有创建其他文件 我的第一次尝试是这样的: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
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/
)。jeez.这看起来是个好主意。我确实希望递归地检查(因为测试涉及子目录和目录)为了在文件名中也允许空白,我想我不是使用checkdirectory foo/foo/bar/
而是使用ls-l
实际上,计算目录中元素数量的正确命令是find-exec-echo-found;
感谢您的反馈。一个问题。我们如何在子目录中提供文件名?我可以假设路径名是按照Léa Gris的回答中所述提供的吗?我已经更新了该问题,以便在调用我的wishlist函数时使用子目录中的内容。谢谢您的回答。我已经更新了我的答案根据find“${testdir}”-mindepth 1-printf.| wc-c