Другой вариант - использовать: sudo iotop -aoP
-a Will show accumulated output
-o Will only output
-P Will only show processes instead of threads
Эта программа сообщит вам, сколько процесс записал на диск и прочитал с диска с момента запуска iotop.
Попробуйте сegrep
egrep 'pattern1|pattern2' file | grep -v -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'
С помощью GNU grep
вы можете передать оба слова в grep
, а затем удалить строки, содержащие оба шаблона.
$ cat testfile.txt
abc
def
abc def
abc 123 def
1234
5678
1234 def abc
def abc
$ grep -w -e 'abc' -e 'def' testfile.txt | grep -v -e 'abc.*def' -e 'def.*abc'
abc
def
Подойдет инструмент, отличный от grep
.
При использовании perl, например, команда будет:
perl -ne 'print if /pattern1/ xor /pattern2/'
perl -ne
запускает команду, заданную для каждой строки стандартного ввода, которая в этом случае печатает строку, если она соответствует /pattern1/ xor /pattern2/
или, другими словами, соответствует одному шаблону, но не другому (эксклюзивному или ).
Это работает для шаблона в любом порядке и должно иметь лучшую производительность, чем многократные вызовы grep
, а также меньше печатать.
Или, еще короче, с помощью awk:
awk 'xor(/pattern1/,/pattern2/)'
или для версий awk безxor
:
awk '/pattern1/+/pattern2/==1`
В логических терминах вы ищете A xor B, что может быть записано как
(А, а не Б)
или
(Б, а не А)
Учитывая, что в вашем вопросе не упоминается, что вы заинтересованы в порядке вывода, пока отображаются совпадающие строки, логическое расширение A xor B чертовски просто в grep:
$ cat << EOF > foo
> a b
> a
> b
> c a
> c b
> b a
> b c
> EOF
$ grep -w 'a' foo | grep -vw 'b'; grep -w 'b' foo | grep -vw 'a';
a
c a
b
c b
b c
Для следующего примера:
# Patterns:
# apple
# pear
# Example line
line="a_apple_apple_pear_a"
Это можно сделать только с помощью grep -E
, uniq
и wc
.
# Grep for regex pattern, sort as unique, and count the number of lines
result=$(grep -oE 'apple|pear' <<< $line | sort -u | wc -l)
Если grep
скомпилирован с регулярными выражениями Perl, вы можете сопоставить последнее вхождение вместо того, чтобы переходить кuniq
:
# Grep for regex pattern and count the number of lines
result=$(grep -oP '(apple(?!.*apple)|pear(?!.*pear))' <<< $line | wc -l)
Вывод результата:
# Only one of the words exists if the result is < 2
((result > 0)) &&
if (($result < 2)); then
echo Only one word matched
else
echo Both words matched
fi
Один вкладыш -:
(($(grep -oP '(apple(?!.*apple)|pear(?!.*pear))' <<< $line | wc -l) == 1)) && echo Only one word matched
Если вы не хотите жестко -кодировать шаблон, его сборку с переменным набором элементов можно автоматизировать с помощью функции.
Это также можно сделать изначально в Bash как функцию без конвейеров или дополнительных процессов, но это будет более сложно и, вероятно, выходит за рамки вашего вопроса.
С grep
реализациями, которые поддерживают perl -например, регулярные выражения (например pcregrep
или GNU или ast -open grep -P
), вы можете сделать это за один grep
вызов с помощью:
grep -P '^(?=.*pat1)(?!.*pat2)|^(?=.*pat2)(?!.*pat1)'
То есть найти строки, которые соответствуют pat1
, но не pat2
, или pat2
, но не pat1
.
(?=...)
и (?!...)
— соответственно операторы просмотра вперед и отрицательного просмотра вперед. Таким образом, технически вышеприведенное ищет начало субъекта (^
), если за ним следует .*pat1
, а не следует .*pat2
, или то же самое с pat1
и pat2
в обратном порядке.
Это неоптимально для строк, содержащих оба шаблона, поскольку тогда их будут искать дважды. Вместо этого вы можете использовать более продвинутые операторы perl, такие как:
grep -P '^(?=.*pat1|())(?(1)(?=.*pat2)|(?!.*pat2))'
(?(1)yespattern|nopattern)
совпадает с yespattern
, если совпадает1
st группа захвата (пустая ()
выше ), и nopattern
в противном случае. Если это ()
совпадает, это означает, что pat1
не совпадает, поэтому мы ищемpat2
(положительный просмотр вперед ), и мы ищем , а не pat2
, иначе (отрицательный просмотр вперед ).
С помощью sed
вы можете написать это:
sed -ne '/pat1/{/pat2/!p;d;}' -e '/pat2/p'