我正在尝试构建要从查找命令中排除的目录列表。不幸的是,其中一些目录中有空格。例如,假设我有一个myList
包含三个目录的列表,其中第二个目录称为“bc”
/bin/bash
myList="a \\
b c \\
d"
我无法说服“bash”不要将第二行分成两个单独的标记。
例如,这段代码
dirList=
stringArray=($myList)
for i in "${stringArray[@]}" ; do
dirList="$dirList -name $i -prune -o"
echo "$dirList"
echo " "
done
返回这个:
-name a -prune -o
-name a -prune -o -name b -prune -o
-name a -prune -o -name b -prune -o -name c -prune -o
-name a -prune -o -name b -prune -o -name c -prune -o -name d -prune -o
但我想让它回来
-name a -prune -o
-name a -prune -o -name b c -prune -o
-name a -prune -o -name b c -prune -o -name d -prune -o
处理空格的明显方法是将第二行定义为"b c"
但是然后我嵌套了双引号。我已经尝试过(我相信)网络上有关处理嵌套引号的所有建议,但没有一个对 m 有用。有人可以建议如何做到这一点吗?
答案1
为什么不从一开始就将列表简单地定义为数组,而不是定义为字符串,然后解析为数组?这样您就可以创建一个由双引号引起来的字符串数组,能够以非标记化的方式处理空格?
弗雷克斯:
#!/bin/bash
myList=("a" "b c" "d")
dirList=
stringArray=$myList
for i in "${stringArray[@]}" ; do
dirList="$dirList -name $i -prune -o"
echo "$dirList"
echo " "
done
答案2
您也不需要该字符串-name a -prune -o name b c -prune ...
,因为实际运行的命令不是单个字符串,而是多个字符串。只是当您编写 时foo bar "a b"
,shell 会解释引号并在不带引号的空格上分割命令行,为您提供三个字符串foo
,bar
和a b
。同样,您最终想要的find
是参数-o
、-name
、等a b
。-prune
如果您有字符串-o -name a b -prune
,则很难将字符串拆分为其他空格,但是不是a
在和之间划分b
。
首先,您需要某种方法来读取换行符分隔的名称列表,而不破坏各个行。既然您提到了 Bash,就有了mapfile
( readarray
) 命令。现在我们假设您在另一个文件中有该名称列表。然后,
readarray -t names < listfile
names
将用文件的内容填充数组,每行一个条目。
请注意,在您的问题中,字符串 inmyList
还包含第二个和第三个目录前面的反斜杠和空格,如果您像这样存储列表,您可能需要清理它们。或者您可以直接将列表存储为数组,例如@James S.的回答。
然后,第二个问题是构建 的参数列表find
。在那里,您还需要一个数组来保持参数完整且独立。所以,
args=()
for n in "${names[@]}"; do
args+=(-name "$n" -prune -o)
done
将用参数填充数组args
。然后你可以用它作为
find ... "${args[@]}"
另外,您不需要重复-prune
,您可以将整个内容括在括号中,并且只-prune
在外部(例如在命令行上)使用一次,您可以使用... "(" -name this -o -name that ")" -prune ...
并且可以填充类似这样的数组
args=("(")
for n in "${names[@]}"; do
args+=(-name "$n" -o)
done
unset "args[${#args[@]} - 1]" # remove the last -o
args+=( ")" -prune )
看:
答案3
我想你可以使用特殊变量 IFS
#!/bin/bash
OFS=$IFS
IFS=$'\n'
myList="a \\
b c \\
d"
dirList=
stringArray=($myList)
for i in "${stringArray[@]}" ; do
dirList="$dirList -name $i -prune -o"
echo "$dirList"
echo " "
done
IFS=$OFS
这是给定的输出:
-name a \ -prune -o
-name a \ -prune -o -name b c \ -prune -o
-name a \ -prune -o -name b c \ -prune -o -name d -prune -o