用于处理(文件夹)名称列表的 Bash 脚本

用于处理(文件夹)名称列表的 Bash 脚本

我正在尝试创建一个 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}

相关内容