stackoverflow 的忠实粉丝。我自己是一个初学者,在这个网站上找到了很多帮助,但现在遇到了问题。
今天我有一个如下所示的功能。
我为写入的每个新行读取一个文本文件(data.txt)。如果文本行包含数组“pets”中包含的任何单词,则会将该行写入另一个文本文件 pets.txt,但忽略其他行。
我如何反转该功能?
我希望能够使用 Array(badword) 阻止坏词,以便这些词不会写入文件 petslist.log
pets.filter 包含
pets=(
'Dog'
'Cat'
'Mouse'
'Horse'
)
badword.filter 包含
badword=(
'Stupid'
'Dumb'
'Bad'
)
script.sh 包含
#!/bin/bash
source /home/pi/pets.filter
source /home/pi/badword.filter
while IFS='' read -r line
do
while [ "${pets[count]}" != "" ]
do
if [ "${line/${pets[count]}}" != "$line" ] ; then
echo "$line" >> /logs/petslist.log
fi
count=$(( $count + 1 ))
done
答案1
如果badwords
实际上是一个数组字,那么你可能想这样使用grep -w
:
-w, --word-正则表达式
仅选择包含构成整个单词的匹配项的行。测试是匹配的子字符串必须位于行的开头,或者前面有一个非单词组成字符。同样,它必须位于行尾或后跟非单词组成字符。单词组成字符是字母、数字和下划线。如果还指定了 -x,则此选项无效。
所以在你的情况下
# Declare some constants
readonly bad_words_list="stupid dumb bad" \
out_file="out_file" \
in_file="in_file"
# The function you want
function filter_bad_words() {
# Loop for reading line-by-line
while read -r line
do
# Loop through the list
# Notice that there are no quotes
for bad_word in ${bad_words_list[@]}
do
# Check if there is a bad word
# Options in grep: quiet, ignore case, word
if grep -qiw "$bad_word" <<< "$line"
then
# Print the line with bad word to stderr
echo "Line contains bad word: $line" 1>&2
# Exit from this loop, continue the main one
continue 2
fi
done
# Save line into the out file
# This will not be called if line contains bad word
echo "$line" >> "$out_file"
# Read from file
done < "$in_file"
}
不确定这是否是最有效的解决方案(也可能使用 sed 或 awk),但至少这有效并且是纯 Bash,grep
仅使用
编辑:如果你只是想过滤这些单词而不做其他处理,你也可以grep -o
在这里使用:
# Read file into a variable
filtered="$(< "$in_file")"
# Go through each bad word
for word in ${bad_words_list[@]}
do
# Filter the word
filtered="$(grep -iv "$word" <<< "$filtered")"
done
# Save final result
echo "$filtered" > "$out_file"
答案2
你把事情搞得太复杂了(而且确实不应该使用 shell 循环来处理文本)
pets='Dog
Cat
Mouse
Horse'
badword='Stupid
Dumb
Bad'
grep -Fe "$pets" < input.txt > pets.txt
grep -vFe "$badword" < input.txt > input-without-badword.txt
或者将两者结合起来:
grep -Fe "$pets" < input.txt |
grep -vFe "$badword" > pets-without-badword.txt
grep
接受多行作为模式(或F
带有 的固定字符串-F
),在这种情况下,它会在输入中查找任何这些行。
如果您必须使用数组而不是多行字符串,您可以这样做:
# fish / rc / zsh -o rcexpandparam
grep -F -e$array < input > output
# zsh
grep -F -e$^array < input > output
# mksh / bash / zsh
grep -F "${array[@]/#/-e}" < input > output
# ksh93
grep -F "${array[@]/*/-e\0}" < input > output
虽然在 mksh / ksh93 / zsh / bash 中,您也可以使用换行符连接数组的元素:
IFS=$'\n'
grep -Fe "${array[*]}" < input > output
或者在 zsh 中:
grep -Fe ${(pj[\n])array} < input > output