当某些行包含空格时对列表进行操作

当某些行包含空格时对列表进行操作

我正在尝试构建要从查找命令中排除的目录列表。不幸的是,其中一些目录中有空格。例如,假设我有一个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,bara 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

相关内容