Вы бы хотели использовать только:
find. -name '*.txt' -exec cmd {} \;
форма для тех cmd
s, которые могут принимать только один аргумент. Это не относится к grep
. Сgrep
:
find. -name '*.txt' -exec grep foo /dev/null {} +
(или используйте -H
с GNUgrep
). Подробнее об этом в Recursive grep vs find / -type f -exec grep {} \; Что эффективнее/быстрее?
Теперь для замены, то же самое, perl -pi
может принимать более одного аргумента:
find. -name '*.txt' -type f -exec perl -pi -e s/foo/bar/g {} +
Теперь это будет перезаписывать файлы независимо от того, содержат они foo
или нет. Вместо этого вы можете захотеть (предполагать GNU grep
и xargs
или совместимые):
find. -name '*.txt' -type f -exec grep -l --null foo {} + |
xargs -r0 perl -pi -e s/foo/bar/g
или:
grep -lr --null --include='*.txt' foo. |
xargs -r0 perl -pi -e s/foo/bar/g
Таким образом, перезаписываются только те файлы, которые содержат foo
.
Кстати,--include=*.txt
(--include
является еще одним расширением GNU. )представляет собой шелл-шаблон, поэтому его следует указать в кавычках. Например, если в текущем каталоге есть файл с именем --include=foo.txt
, оболочка расширит --include=*.txt
до него перед вызовом grep
. А если нет, то во многих оболочках вы получите ошибку о том, что glob не соответствует ни одному файлу.
Так и хочетсяgrep --include='*.txt'
stderr
предназначен для письма, а не для чтения. Иногда это dup
ликата stdin
(, например. когда все 3 входа/выхода/ошибки подключены к клемме ). Чтобы прочитать stderr другой программы, вы перенаправляете stderr этой программы на stdin другой.
напр. to направляет stdout
в файл, а stderr
— в ./myprograms
stdin
.
command 2>&1 >a_file |./myprogram
Чтобы оболочка установила перенаправление ввода для stderr
, вы должны использовать <
, <<
или <<<
и префикс номера дескриптора файла:
./myprog 2< somefile.txt
или
./myprog 2<<< "some text"
Хотя, если вы перенаправите stderr
таким образом, программа не сможет вывести на него , что будет означать, что вы не увидите никаких сообщений об ошибках программы (или каких-либо библиотек, которые она использует )может попытаться напечатать, и, кроме того, программа получит ошибки при попытке написать эти сообщения.
Возможно, вы захотите еще раз подумать, есть ли какой-то другой способ делать то, что вы делаете. По крайней мере, рассмотрите возможность использования, например. fd 3, если идея состоит в том, чтобы предоставить какой-либо ввод в программу.
Многих удивляет тот факт, что большинство справочников и документации всегда ссылаются на стандартную ошибку как на вывод, что на самом деле она обычно уже открыта для чтения+записи . Ваша программа очень может читать из файлового дескриптора 2.
(Примечание :В этом ответе я использую фактические номера файловых дескрипторов. C-потоки , такие как stderr
, на самом деле не должны соответствовать этим файловым дескрипторам, поскольку программа может изменить их, и это добавляет путаницы в разговоры о том, что делают C-потоки. Ваша программа использует read()
.)
Для программ в сеансах входа в систему, где в родительском процессе не использовалось перенаправление, стандартная ошибка файлового дескриптора 2 ()обычно является дубликатом файлового дескриптора 0 (стандартного ввода ). Оба они ссылаются на одно и то же базовое описание файла , которое обычно является терминалом сеанса входа в систему (, открытым и дублированным ttymon
или, в более старых системах, getty
в самом начале сеанса. ).
Если вы читаете из файлового дескриптора 2, вы получаете тот же ввод, как если бы вы читали из файлового дескриптора 0.
BTW :Чтение файлового дескриптора 2 часто выполнялось для таких вещей, как ввод пароля; до того, как было представлено устройство /dev/tty
, примерно в 1977 году. Причина чтения из файлового дескриптора 2 заключалась в том, чтобы получить ввод с исходного терминала, когда файловый дескриптор 0 был перенаправлен в другое место (, как в случае в середине конвейера, например ).
Несмотря на то, что /dev/tty
доступен уже давно, более 40 лет, POSIX по-прежнему требует, чтобы файловый дескриптор 2 также был открыт для чтения.
Чтение выходных данных файлового дескриптора 2 другой программы — это другое дело. Вы не можете легко сделать это само по себе , не объединяя стандартный вывод со стандартной ошибкой. Обычно это включает серию 3>&1 1>&2 2>&3
или подобных свопов. Несколько оболочек разрешают конвейеры для дескриптора выходного файла 2, вызывая
prog1 2| prog2
Но такие оболочки встречаются редко, и это не то, что нужна вашей программе в любом случае.
Если вы хотите, чтобы ваша программа, читающая из файлового дескриптора 2, читала из чего-то отличного от терминала, вы, конечно, перенаправляете этот файловый дескриптор. Вы могли бы использовать обычный ввод синтаксис перенаправления (оператор <
в оболочке ), но библиотеки в вашей программе или даже другой код, который вы написали в другом месте, будут иметь предположения, что они могут писать в этот файловый дескриптор.
Оболочка позволяет использовать оператор перенаправления <>
, который явно открывает файл как для чтения, так и для записи. Это то, что вы используете при перенаправлении файлового дескриптора вашей программы 2.
./myprogram 2<>filename
Помимо перенаправления оболочки, существует множество инструментов, позволяющих манипулировать файловыми дескрипторами. Например, :С цепочкой Лорана Берко -, загружающейredirfd
инструмент, который поставляется с execline,это перенаправление больше похоже на вашу гипотезу:
redirfd -u 2 filename./myprogram
Существует также синтаксис оболочки в оболочках Bourne Again и Z (, но не в оболочках Almquist )для предоставления «здесь документы» и «здесь строки» для файлового дескриптора 2. Обратите внимание, что файловый дескриптор 2 в этом случае открывается только для чтения этими оболочками.
./myprogram 2<<< "here string"
С такими оболочками, как bash
и zsh
(, но не с простым POSIX sh
), вы можете перенаправить стандартную ошибку одной программы на стандартный ввод другой программы через firstprogram 2> >(second program)
.
Пример:
$ perl -E 'say "perl stdout"; warn "perl stderr\n"' 2> >(awk '{print "awk", $0}')
perl stdout
awk perl stderr