Felrood от Дуги, форумы Linux предоставили решение и я хотел бы совместно использовать его здесь и закрыть этот вопрос.
Gedit, кажется, отображает данные из stdin в новом "Несохраненном документе". Например:
echo "foobar" | gedit
То, что может быть сделано, является этим:
щелкните правой кнопкой по кнопке Kmenu->, приложения редактирования-> находят gedit там (для меня, который является "утилитами")-> помещенный "gedit, 1$ сохраняет
Для меня, который решил проблему, неважно, использую ли я участника общественной кампании, дельфина, alt+f2 или что-то еще..
С инструментами GNU:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
Можно сделать стандартно:
find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;
Но это выполнило бы две власти на файл. Постараться не выполнять это многие grep
s и все еще быть портативным, все еще позволяя любой символ в именах файлов, Вы могли сделать:
convert_to_xargs() {
sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
{
if (NR > 1) {
printf "%s", line
if (!index($0, "//")) printf "\\"
print ""
}
line = $0
}'
END { print line }'
}
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
Причем идея состоит в том, чтобы преобразовать вывод find
в формат, подходящий для xargs (который ожидает пробел (SPC/вкладка/NL и другие пробелы от Вашей локали с некоторыми реализациями xargs
) разделенный список слов, где единственный, двойные кавычки и обратные косые черты может выйти из пробелов и друг друга).
Обычно Вы не можете выполнить последующую обработку вывод find -print
, потому что это разделяет имена файлов с символом новой строки и не выходит из символов новой строки, которые найдены в именах файлов. Например, если мы видим:
./a
./b
У нас нет способа знать, является ли это одним названным файлом b
в названном каталоге a<NL>.
или если это - эти два файла a
и b
.
При помощи .//.
, потому что //
не может появиться иначе в пути к файлу, как произведено find
(потому что нет такой вещи как каталог с пустым названием и /
не позволяется в имени файла), мы знаем что, если мы видим строку, которая содержит //
, затем это - первая строка нового имени файла. Таким образом, мы можем использовать это awk
управляйте для выхода из всех символов новой строки, но те, которые предшествуют тем строкам.
Если мы берем пример выше, find
произвел бы в первом случае (один файл):
.//a
./b
К которому выходит awk:
.//a\
./b
Так, чтобы xargs
рассматривает его как один аргумент. И во втором случае (два файла):
.//a
.//b
Который awk
уехал бы, как, таким образом, xargs
видит два аргумента.
Если файлы находятся в единственном каталоге, и их имя не содержат пространство, вкладку, новую строку, *
, ?
ни [
символы и не запускаются с -
ни .
, это получит список файлов, содержащих ME, затем сузит это к тем, которые также содержат, НАХОДЯТ.
grep -l FIND `grep -l ME *`
С awk
вы также можете запустить:
find . -type f -exec awk 'BEGIN{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; END{if (cx > 0 && cy > 0) print FILENAME}' {} \;
Он использует cx
и cy
для подсчета строк, соответствующих FIND
и соответственно ME
. В блоке END
, если оба счетчика> 0, он печатает FILENAME
.
Это будет быстрее / эффективнее с gnu awk
:
find . -type f -exec gawk 'BEGINFILE{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; ENDFILE{if (cx > 0 && cy > 0) print FILENAME}' {} +
Глядя на принятый ответ, он кажется более сложным, чем должен быть. Версии GNU find
, grep
и xargs
поддерживают строки, заканчивающиеся NULL -. Это так же просто, как:
find. -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l ME
Вы можете изменить команду find
для фильтрации нужных файлов, и она работает с именами файлов, содержащими любой символ; без дополнительной сложности разбора sed
. Если вы хотите продолжить обработку файлов, добавьте еще один --null
к последнемуgrep
find. -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l --null ME | xargs -0 echo
И, как функция:
find_strings() {
find. -type f -print0 | xargs -0 grep -l --null "$1" | xargs -0 grep -l "$2"
}
Очевидно, используйте принятый ответ, если вы не используете версии этих инструментов GNU.
Или используйте egrep -e
или grep -E
вот так:
find. -type f -exec egrep -le '(ME.*FIND|FIND.*ME)' {} \;
или
find. -type f -exec grep -lE '(ME.*FIND|FIND.*ME)' {} +
+
заставляет найти (, если поддерживается )добавить несколько имен файлов (пути )в качестве аргументов к команде -exec
ed. Это экономит процессы и намного быстрее, чем \;
, который вызывает команду один раз для каждого найденного файла.
-type f
соответствует только файлам, чтобы избежать поиска в каталоге.
'(ME.*FIND|FIND.*ME)'
— это регулярное выражение, соответствующее любой строке, содержащей «ME», за которой следует «FIND» или «FIND», за которой следует «ME». (одинарные кавычки, чтобы оболочка не интерпретировала специальные символы ).
Добавьте -i
к команде grep
, чтобы сделать ее нечувствительной к регистру -.
Чтобы найти только те строки, в которых «НАЙТИ» стоит перед «ME», используйте 'FIND.*ME'
.
Требуются пробелы (1 или более, но ничего больше )между словами:'FIND +ME'
Разрешить пробелы (0 или более, но ничего другого )между словами:'FIND *ME'
Комбинации с регулярными выражениями бесконечны, и если вас интересует сопоставление только по строке -в -и -временной основе, egrep является очень мощным.
Примечание.:Вы должны сами проверить, какой из них самый быстрый.
grep -rlzE '(TermOne.*TermTwo)|(TermTwo.*TermOne)' # GNU grep
find. -type f -exec grep -q 'TermOne' {} \; \
-exec grep -q 'TermTwo' {} \; \
-print
awk '/TermOne/{if(p==0)p=1; if(p==2)p=3}
/TermTwo/{if(p==0)p=2; if(p==1)p=3}
p==3{print FILENAME;p=0;nextfile}'./*
Невозможно построить регулярное выражение, которое могло бы сопоставлять две отдельные строки в файле.
Можно искать два термина с любым чередованием:
grep -E '(TermOne.*TermTwo)|(TermTwo.*TermOne)' file
или просмотр вперед:
grep -P '(?=.*TermOne)(?=.*TermTwo)' file
но только если два термина находятся в одной строке
Также можно сделать так, чтобы весь файл действовал как один файл (, если файл не содержит NUL. Текстовые файлы Unix не )с параметром GNU grep -z
:
grep -zE '(TermOne.*TermTwo)|(TermTwo.*TermOne)' file
Невозможно использовать -z
с -P
одновременно, поэтому на сегодняшний день невозможны никакие упреждающие решения.
Другой вариант — выполнить grep дважды:
<file grep 'TermOne' | grep -q 'TermTwo'
Код выхода всего канала будет сигнализировать 0
, только если оба термина были найдены в одном файле.
Или, используя awk:
awk '/TermOne/{if(p==0)p=1; if(p==2)p=3}
/TermTwo/{if(p==0)p=2; if(p==1)p=3}
p==3{print "both terms found"; exit}' file
Первые два приведенных выше решения будут работать для рекурсивного списка всех файлов путем добавления параметров-r
(recursive, после чего нет необходимости в имени файла ),-l
(список совпадающих имен файлов )и-z
(предполагается, что весь файл представляет собой одну строку ).
grep -rlzE '(TermOne.*TermTwo)|(TermTwo.*TermOne)'
Или, используя find (два вызова grep):
find. -type f -exec grep -q 'TermOne' {} \; \
-exec grep -q 'TermTwo' {} \; \
-print
Или,при использовании awk (глобус будет включать только PWD):
awk '/TermOne/{if(p==0)p=1; if(p==2)p=3}
/TermTwo/{if(p==0)p=2; if(p==1)p=3}
p==3{print FILENAME;p=0;nextfile}'./*
find ... -print0
иgrep --null
вместо этого? – razzed 28.06.2017, 18:32grep --null
(иначе-Z), используется в первом, но расширение GNU.-print0
(другое расширение GNU), не помог бы здесь. – Stéphane Chazelas 28.06.2017, 18:56