bash - 从数组构建选项时,如何在查找命令中使用括号“()”?
问题描述
我有一个看起来像这样的功能。我已经剥离了错误处理,函数之外的命令是为了确保我在示例中找到了一些东西。
#!/bin/bash
findfiles() {
local path=$1
local mtime=$2
local prunedirs=$3
local -a fopts
fopts+=("$path")
[[ -n $prunedirs ]] && {
fopts+=('-type' 'd')
fopts+=('(' '-path')
fopts+=("${prunedirs// / -o -path }")
fopts+=(')' '-prune' '-o')
}
fopts+=('-type' 'f')
fopts+=('-writable')
fopts+=('-mtime' "+$mtime")
[[ -n $prunedirs ]] && fopts+=('-print')
echo "find ${fopts[*]}"
find "${fopts[@]}"
}
mkdir -p dir1/{dir2,dir3}
touch dir1/5daysago.txt -mt "$(date -d 'now - 5 days' +%Y%m%d%H%M)"
touch dir1/dir2/6daysago.txt -mt "$(date -d 'now - 6 days' +%Y%m%d%H%M)"
touch dir1/dir3/10daysago.txt -mt "$(date -d 'now - 10 days' +%Y%m%d%H%M)"
echo '---------------------------------------------'
findfiles dir1 4
echo '---------------------------------------------'
findfiles dir1 4 'dir1/dir2'
echo '---------------------------------------------'
findfiles dir1 4 "dir1/dir2 dir1/dir3"
这将输出以下内容:
---------------------------------------------
find dir1 -type f -writable -mtime +4
dir1/dir2/6daysago.txt
dir1/dir3/10daysago.txt
dir1/5daysago.txt
---------------------------------------------
find dir1 -type d ( -path dir1/dir2 ) -prune -o -type f -writable -mtime +4 -print
dir1/dir3/10daysago.txt
dir1/5daysago.txt
---------------------------------------------
find dir1 -type d ( -path dir1/dir2 -o -path dir1/dir3 ) -prune -o -type f -writable -mtime +4 -print
dir1/dir2/6daysago.txt
dir1/dir3/10daysago.txt
dir1/5daysago.txt
请注意,第三次尝试不会修剪目录。如果我复制并粘贴查找(转义括号)它可以正常工作。
$ find dir1 -type d \( -path dir1/dir2 -o -path dir1/dir3 \) -prune -o -type f -writable -mtime +4 -print
dir1/5daysago.txt
我究竟做错了什么?
解决方案
更改echo "find ${fopts[*]}"
为declare -p fopts
明确打印选项。这样做将表明该-o -path
部分被添加为一个单词:
$ declare -p fopts
declare -a fopts=(
[0]="dir1" [1]="-type" [2]="d" [3]="(" [4]="-path"
[5]="dir1/dir2 -o -path dir1/dir3" [6]=")" [7]="-prune" [8]="-o" [9]="-type" [10]="f"
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[11]="-writable" [12]="-mtime" [13]="+4" [14]="-print"
)
要修复它,您需要将每个目录添加到单独修剪到数组中,例如:
local prunedirs=("${@:3}")
...
fopts+=(-type d '(' -false)
for dir in "${prunedirs[@]}"; do
fopts+=(-o -path "$dir")
done
fopts+=(')' -prune -o)
我已经切换prunedirs
到一个数组,所以它可以处理带有空格的目录名。
它从初始-false
检查开始,因此无需检查是否prunedirs
为空。如果它是空的,则仍然会添加整个内容,但因为它只是说它-type d '(' -false ')' -prune -o
是无操作的。
另外,请注意您不必引用每个参数。可以编写-type d
并且不加引号,就像在命令行中键入它们一样。只有'('
并且')'
需要单引号。
推荐阅读
- javascript - 预期条件失败:等待包含 style="display: none;" 的元素可点击元素
- performance - 是否应该将结构元组作为记忆函数的参数?
- angular - 调用 Observable 并在里面订阅
- spring - Spring Data 自定义基础仓库 elasticsearchrepository
- azure-devops - VSTS 扩展:从新的 repo 初始化或创建一个 master 分支
- uwp - UWP Wifi Direct 获取异常代码 0x288 (ERROR_DEVICE_ENUMERATION_ERROR)
- python-3.x - 如何将 Excel 和 Python 打包在一起并分发给业务用户?
- php - 如何从 MySQL 中获取数据作为数组并根据 PHP 中的下拉选择动态填充文本字段
- polymer - 聚合物初始化(无响应)
- c - 以乘法格式显示的素数因子