1

У меня есть многострочная переменная Bash: $WORDS содержащая одно слово в каждой строке.
У меня есть другая многострочная переменная Bash: $LIST также содержащая одно слово в каждой строке.

Я хочу удалить $LIST из любого слова в $WORDS .

В настоящее время я делаю это с while read и grep но это не сексуально.

WORDS=$(echo -e 'cat\ntree\nearth\nred')
LIST=$(echo -e 'abcd\n1234\nred\nwater\npage\ncat')
while read -r LINE; do
    LIST=$(echo "$LIST" | grep -v "$LINE")
done <<< "$WORDS"
echo "$LIST"

Я думаю, что могу сделать это с помощью awk но мне не удалось заставить его работать.
Может кто-нибудь объяснить мне, как это сделать с помощью awk?

2 ответа2

3

Это должно выполнить то, что вы пытаетесь сделать.

WORDS=$(echo -e 'cat\ntree\nearth\nred')
LIST=$(echo -e 'abcd\n1234\nred\nwater\npage\ncat')

echo "$LIST" | awk -v WORDS="$WORDS" '
BEGIN {
  split(WORDS,w1,"\n")
  for (w in w1) { w2[w1[w]] = 1 }
}
{
  if (w2[$0] != 1) { print $0 }
}'

Вот как это работает. Сначала я использую опцию -v в командной строке awk, чтобы передать список слов как переменную. Эта переменная будет видна внутри программы awk с именем WORDS.

Блок BEGIN выполняется перед обработкой любого ввода. Содержит две строки

split(WORDS,w1,"\n")

Эта команда split берет список WORDS и превращает его в массив с именем w1.

for (w in w1) { w2[w1[w]] = 1 }

Это цикл for проходит по массиву w1 и генерирует ассоциативный массив w2. Преобразование массива в ассоциативный массив улучшит производительность.

Далее у нас есть основная часть цикла, которая обрабатывает LIST.

if (w2[$0] != 1) { print $0 }

Это будет проверять каждую строку ввода по нашему ассоциативному массиву и печатать строку, только если слово не было найдено. Поскольку мы присвоили каждому ключу значение 1 в нашем блоке BEGIN, нам нужно только проверить, равно ли значение этого ключа 1, чтобы узнать, определено ли оно.

2

Я предлагаю

echo "$LIST" | grep -vf <(echo "$WORDS")

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .