我有一个字符串列表,我想从另一个字符串的超集中删除,而不是以任何特定的顺序,从而构建一个新的集合。这在巴什是可行的吗?
答案 0 :(得分:5)
看起来你正在寻找比O(nm)运行时间更好的东西,所以这就是答案。 Fgrep或grep -F使用Aho-Corasick算法从固定字符串列表中生成单个FSM,因此检查SET2中的每个字需要O(字长)时间。这意味着该脚本的整个运行时间为O(n + m)。
(显然,运行时间也取决于单词的长度)
[meatmanek@yggdrasil ~]$ cat subtract.sh
#!/bin/bash
subtract()
{
SET1=( $1 )
SET2=( $2 )
OLDIFS="$IFS"
IFS=$'\n'
SET3=( $(grep -Fxv "${SET1[*]}" <<< "${SET2[*]}") )
IFS="$OLDIFS"
echo "${SET3[*]}"
# SET3 = SET2-SET1
}
subtract "$@"
[meatmanek@yggdrasil ~]$ . subtract.sh
[meatmanek@yggdrasil ~]$ subtract "package-x86 test0 hello world" "computer hello sizeof compiler world package-x86 rocks"
computer sizeof compiler rocks
[meatmanek@yggdrasil ~]$
答案 1 :(得分:2)
> echo "aa b1 c b2 d" |xargs -d' ' -n 1
aa
b1
c
b2
d
> echo "aa b1 c b2 d" |xargs -d' ' -n 1| grep "^b"
b1
b2
答案 2 :(得分:1)
我认为你必须至少要描述你想要提取的字符串子集的参数。但是,如果它是类似文本字段的数据,请查看awk。
答案 3 :(得分:1)
对内置命令hash
的任何丑陋滥用怎么样?
#!/bin/bash
set -eu
filter_out() {
local words="$2" words_to_remove="$1"
( # do this in a subshell to avoid contaminating the main script
set +e
hash -r
hash -p bogus-placeholder $words
hash -d $words_to_remove > /dev/null 2>&1
left=''
for word in $words; do
hash -t "$word" > /dev/null 2>&1 && left="${left}${left:+ }$word"
done
printf '%s\n' "$left"
)
}
filter_out "package-x86 test0 hello world" "computer hello sizeof compiler world package-x86 rocks test0"
w='foo bar baz quux toto'
d='baz toto quux'
filter_out "$d" "$w"
答案 4 :(得分:0)
这使用grep来查看是否必须删除一个单词,但这不是纯粹的BASH,它可能比其他选项更快(见下文)
#!/bin/bash
REMOVE="package-x86 test0 hello world"
WORDBAG="computer hello sizeof compiler world package-x86 rocks test0"
OFS=$IFS
IFS=" "
WORDBAG_ARRAY=($WORDBAG)
IFS=$OFS
RESULT=""
for str2 in ${WORDBAG_ARRAY[@]}
do
echo $REMOVE | grep $str2 >/dev/null
if [[ $? == 1 ]] #Not Found
then
RESULT="$RESULT $str2"
fi
done
echo $RESULT
这有点冗长,使用BASH数组,并且是O(N * M),但有效。
#!/bin/bash
REMOVE="package-x86 test0 hello world"
WORDBAG="computer hello sizeof compiler world package-x86 rocks test0"
OFS=$IFS
IFS=" "
REMOVE_ARRAY=($REMOVE)
WORDBAG_ARRAY=($WORDBAG)
IFS=$OFS
RESULT=""
for str2 in ${WORDBAG_ARRAY[@]}
do
found=0
for str1 in ${REMOVE_ARRAY[@]}
do
if [[ "$str1" == "$str2" ]]
then
found=1
fi
done
if [[ $found == 0 ]]
then
RESULT="$RESULT $str2"
fi
done
echo $RESULT
答案 5 :(得分:0)
#!/bin/bash
SET1="package-x86 test0 hello world"
SET2="computer hello sizeof compiler world package-x86 rocks test0"
awk -v s1="$SET1" -v s2="$SET2" 'BEGIN{
m=split(s1,set1)
n=split(s2,set2)
for(i=1;i<=n;i++){
for (j=1;j<=m;j++){
if ( set1[j] == set2[i]){
delete set2[i]
}
}
}
for(i in set2) if (set2[i]!="") {print set2[i]}
}'
输出
# ./shell.sh
compiler
rocks
computer
sizeof
答案 6 :(得分:0)
这是什么,O(n)或O(n + m)?
#!/bin/bash
SET1="package-x86 test0 hello world"
SET2="computer hello sizeof compiler world package-x86 rocks test0"
for i in $SET2
do
[[ ! $SET1 =~ $i ]] && SET3="${SET3:+${SET3} }$i"
done
echo "..${SET3}.."
运行它:
$ ./script
..computer sizeof compiler rocks..
答案 7 :(得分:0)
不使用任何特定于bash或外部的命令:
SET1="package-x86 test0 hello world"
SET2="computer hello sizeof compiler world package-x86 rocks test0"
SET3=
for arg in $SET2; do
case $SET1 in
$arg\ * | *\ $arg | *\ $arg\ *) ;;
*) SET3="$SET3 $arg" ;;
esac
done