我正在尝试这样做,实现这一目标的最有效方法是什么?
#!/bin/bash
# Remove DOGS from CATSNDOGS to give CATS
DOGS="fido rover oscar bowwow spike max"
CATSNDOGS="bowwow figaro pussy oscar boots rover kitty max spike meowser fluffles fido"
CATS="" #?? How do I do this?
答案 0 :(得分:2)
comm
答案很有创意,但当然不是唯一的方法。您也可以在bash中完全执行此操作,而无需使用额外的工具。
#!/bin/bash
DOGS="fido rover oscar bowwow spike max"
CATSNDOGS="bowwow figaro pussy oscar boots rover kitty max spike meowser fluffles fido"
# make an associative array...
declare -A dogs_a
for dog in $DOGS; do
dogs_a[$dog]=1;
done
CATS=""
# step through everything
for beast in $CATSNDOGS; do
# if it's not a dog...
if [ -z "${dogs_a[$beast]}" ]; then
CATS="$CATS $beast"
fi
done
echo $CATS
请注意,这也依赖于空格作为字段分隔符,您应该阅读在bash编程时始终将变量包装在引号中。
答案 1 :(得分:2)
Pure Bash(注意空白):
CATS=" $CATSNDOGS "
for dog in $DOGS ; do
CATS=${CATS/ $dog / }
done
echo -e "CATS : '$CATS'"
结果:
CATS : ' figaro pussy boots kitty meowser fluffles '
答案 2 :(得分:1)
您可以使用程序comm
执行此操作。 -3
选项摆脱了匹配的行(不是单词),输入需要进行排序,因此还有更多内容。像这样:
comm -3 <(echo $DOGS | tr ' ' '\n' | sort) <(echo $CATSNDOGS | tr ' ' '\n' | sort)
为了支持原始输入格式(带空格)并避免创建临时文件,我们将空格转换为换行符,对两个输入进行排序,并将它们用作comm
的“虚拟”文件参数。
编辑:我没有捕获输出,它只是打印到stdout。您可以说CATS=$(...)
来存储它,但如果这是您想要的,您可能需要稍微按摩它以回到空间。
答案 3 :(得分:1)
另一种方法:
for i in $CATSNDOGS
do
skip=0
for j in $DOGS
do
if [ "$j" == "$i" ]; then
skip=1
else
continue
fi
done
if [ "$skip" == "0" ]; then
CATS="$CATS $i"
else
continue
fi
done
echo -e "cats: $CATS"
然而,我更喜欢带有关联数组的ghoti版本。
答案 4 :(得分:1)
在单个命令中,保持猫的顺序,但使用复杂的sed
逻辑:
sed -e 'N;s/^/ /;s/$/ /;s/\n/ \n /;bbegin' \
-e ':begin;s/ \(.*\) \(.*\)\n\(.*\) \1 / \2\n\3 /;tbegin' \
-e 's/^ //;s/ \n //' << EOF
$CATSNDOGS
$DOGS
EOF
这是逻辑解释:
$CATSNDOGS
和$DOGS
放在同一行,由新行(\n
)分隔。$CATSNDOGS
和$DOGS
之前和之后添加空格,以简化以下逻辑。修改强>:
我意识到,如果一只狗不在$CATSNDOG
或者一只狗在$CATSNDOG
中两次,那么上面就会中断。改进版本是:
sed -e 'N;s/^/ /;s/$/ /;s/\n/ \n /;bbegin' \
-e ':begin;s/ \(.*\) \(.*\)\n\(.*\) \1 / \2\n\3 \1 /;tbegin' \
-e 's/^ //;s/ \n.*//' << EOF
$CATSNDOGS
$DOGS
EOF
答案 5 :(得分:0)
这是join
使用打印无法使用的行(-a
)参数的作业。然后我们保持以空格结尾的行,并删除该空格。为避免使用临时文件,我们使用bash
进程替换。
join -a 1 -j 1 -o 1.1,2.1 \
<(tr " " "\n" <<< "$CATSNDOGS" | sort) \
<(tr " " "\n" <<< "$DOGS" | sort) | sed -e '/ $/!d;s/ //'
它会丢失$CATSNDOGS
的初始顺序,但我们可以轻松添加cat -n
和sort
以取回初始排序。
要将其放回变量中,请执行以下操作:
CATS="$(join -a 1 -j 1 -o 1.1,2.1 \
<(tr " " "\n" <<< "$CATSNDOGS" | sort) \
<(tr " " "\n" <<< "$DOGS" | sort) | sed -e '/ $/!d;s/ //' | paste -s -d " ")"
答案 6 :(得分:0)
另一种仅限bash的方法
cats=()
for animal in $CATSNDOGS; do
if [[ " $DOGS " == *" $animal "* ]]; then
# animal is a dog
else
cats+=$animal
fi
done
echo "${cats[@]}"