我正在尝试创建一个 bash 脚本,该脚本迭代一个包含文件夹名称列表的文本文件,并检查某个路径中是否缺少任何这些文件夹,在本例中是一个名为2021
.
我的 list.txt 文件包含一个如下列表:
100001
100002
100003
100004
...
我有一个目录(所谓的2021
),其中包含我想检查其名称的子文件夹
100001
100002
100004
...
现在,在此示例中,脚本应指出该文件夹100003
丢失。该脚本的目的只是查找路径中缺少文本文件中列出的哪些文件夹
到目前为止,我有:
while IFS= read -r line; do
if [[ ! -d "2021/$line" ]]; then
echo $line is missing
fi
done <<< $(cat list.txt)
但这段代码只是打印目录中存在的所有文件夹2021
,所以我猜测语句中存在问题IF
,但我无法弄清楚。
答案1
我假设您正在包含文件夹的路径之外运行 shell 脚本2021
。
具有这样的结构:
$> tree
#output:
.
├── 2021
│ ├── 100000
│ ├── 100001
│ ├── 100002
│ ├── 100003
│ ├── 100006
│ ├── 100007
│ ├── 100008
│ ├── 100009
│ ├── 100010
│ ├── 100011
│ ├── 100019
│ ├── 100020
├── list.txt
└── script
您应该能够运行当前的脚本,而无需更改任何内容,只需使用:./script
问题是,如果您script
在脚本目录之外运行,代码将无法成功运行。所以我建议你将脚本更改为:
#!/bin/bash
filepath="$(dirname $(readlink -f $0) )"
cd $filepath
while read -r line; do
if [[ ! -d "2021/$line" ]]; then
echo $line is missing
fi
done <<< $(cat list.txt)
#Or:
# done < /paht/to/list.txt
我删除了IFS=
。我不确定你为什么有它,但如果你真的必须使用那就添加它
因此您将能够从任何目录运行脚本,例如./path/to/dir/script
您还可以使用以下命令获取丢失的目录:
#With this code you will get only the missing dirs. The text 'is missing'
#won't appear here
diff --new-line-format="" --unchanged-line-format="" <(sort /path/to/list.txt) <(find . -maxdepth 1 -type d ! -path . -printf '%P\n' | sort)
如果您的文件list.txt
实际上已排序,那么您可以更改<(sort /path/to/list.txt)
为简单/path/to/list.txt
如果您使用上面的代码,请确保您放置在2021
目录下并更改/path/to/list.txt
为实际路径list.txt
答案2
经过几个小时的寻找问题,我终于找到了解决方案。
问题在于该文件最初是在 Windows 操作系统下创建的,然后在 bash shell 中使用,这意味着在 Windows 中,行以换行符和回车符结尾,但在 Unix 中,它们仅以单个换行符结尾。
所以我猜测,当将IF
文件中的名称与文件夹中的名称进行比较时,显然不可能匹配,因为列表文件中的名称有一个额外的回车符,任何人都看不到。
所以我在 unix 下重新创建了该文件,现在,你瞧,我完美地得到了预期的结果。感谢所有试图提供帮助的人。
答案3
我使用 zsh 而不是 bash 是一个选项,您可以使用其优越的 glob 及其数组连接 ( ${A:*B}
) 和减法 ( ${A:|B}
) 运算符:
#! /bin/zsh -
list=path/to/list.txt
dir=path/to/2021
# or list=${1?} dir=${2?}
# for instance to pass those as arguments to the script
expected=( ${(f)"$(<$list)"} )
# or expected=( ${(f)"$(dos2unix < $list)"} )
# if that file is in MS DOS/Windows format
got=( $dir/*(ND/:t) )
# or got=( $dir/*(ND-/:t) )
# to also consider symlinks to directories like your [[ -d ... ]] does
report() {
if (( $# > 1 )); then
print -rC1 -- $1: ' - '$^@[2,-1]
else
print -r -- $1: none
fi
}
report Found ${expected:*got}
report Missing ${expected:|got}
report Unexpected ${got:|expected}