Как избежать команд, переданных для поиска с опцией exec в Linux - PullRequest
6 голосов
/ 06 января 2011

Позвольте мне разбить мою проблему на простейший пример, который я могу.

Создайте тестовый файл, содержащий одну строку текста.

[root@myserver ] /tmp> echo "test ReplaceMe DoNotReplaceMe" > /tmp/daj.txt

У нас есть существующая команда find, которую мы используем для подстановки текста во всех файлах, которые ему соответствуют (в этом примере я упростил эту команду, чтобы она работала только с одним файлом, и удалил другие, которые он выполняет) ,

Проблема в том, что он заменяет «ReplaceMe» везде, где он появляется, а не только тогда, когда это само слово.

[root@myserver ] /tmp> find /tmp/daj.txt -exec sh -c 'f="{}"; sed -e 's/ReplaceMe/#DONE#/gi' "${f#.}" ' \;
test #DONE# DoNot#DONE#

Я написал новую команду sed, которая заменяет «ReplaceMe» только тогда, когда оно само по себе является словом, но НЕ, когда оно является подстрокой другого слова. Вывод этой команды правильный.

[root@myserver ] /tmp> cat /tmp/daj.txt | sed -e 's/\(\W\)\(ReplaceMe\)\(\W\)/\1#DONE#\3/gi'    
test #DONE# DoNotReplaceMe

Когда я пытаюсь включить обновленную команду sed в команду find, она прерывается. Похоже, я столкнулся с проблемой побега, но мне не удалось решить ее, добавив дополнительную побег.

[root@myserver ] /tmp> find /tmp/daj.txt -exec sh -c 'f="{}"; sed -e 's/\(\W\)\(ReplaceMe\)\(\W\)/\1#DONE#\3/gi' "${f#.}" ' \;
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `f="/tmp/daj.txt"; sed -e s/(W)(ReplaceMe)(W)/1#DONE#3/gi "${f#.}" '

Есть ли способ избежать моей команды sed, чтобы я мог выполнить ее с помощью find, или мне нужно искать альтернативное решение?

Обновление: Полная команда find, которую мы выполняем, распечатывает имя файла и разрешения, а затем передает вывод sed в md5sum. Вот пример запуска и сопоставления нескольких файлов:

[root@myserver ] ~> find /tmp -regex '.*daj.*\.txt' -printf '%p %m ' -exec sh -c 'f="{}"; sed  -e 's/ReplaceMe/#DONE#/gi' "${f#.}" | md5sum' \;
/tmp/daj2.txt 644 d52bbd311552234b761bcae694c2055a  -
/tmp/daj.txt 644 d52bbd311552234b761bcae694c2055a  -

Ответы [ 2 ]

2 голосов
/ 06 января 2011

Вы не должны использовать {} непосредственно в оболочке, вместо этого вы должны передавать имена файлов в качестве параметров оболочки. Кроме того, если вы хотите ограничить совпадения целыми словами, используйте \<word\> для sed

Обновление

find /tmp -regex '.*daj.*\.txt' -printf '%p %m ' -exec sh -c "sed  -e 's/\<ReplaceMe\>/#DONE#/gi' \$@ | md5sum" _ {} \;

выход

$ find . -regex '.*daj.*\.txt' -printf '%p %m ' -exec sh -c "sed  -e 's/\<ReplaceMe\>/#DONE#/gi' \$@ | md5sum" _ {} \;
./daj2.txt 664 ea324b4721ed037dbc2402ded4446005  -
./daj.txt 664 0bbb9104da99c1c1187a2a35e6ac0e9b  -
1 голос
/ 06 января 2011

Это не отвечает на ваш вопрос о escape-последовательности, но действительно решает проблему. Я бы в основном использовал xargs с sed вот так:

$ find ~/tmp/data.txt | xargs sed -e 's/\<replaceme\>/1234/'
1234 in this sentance
donotreplaceme in this sentance
$ 

и содержимое файла data.txt:

replaceme in this sentance
donotreplaceme in this sentance

Также, если у вас могут быть имена файлов с пробелами, используя параметр -print0, который сообщает find для вывода списка файлов в виде строк с нулевым символом в конце. В противном случае команда find будет интерпретировать пространство в имени файла как конец имени файла. Затем при использовании xargs вам нужно использовать параметр -0, чтобы сообщить xargs, что вход является списком строк с нулевым символом в конце. Пример ниже:

find /somedir -print0 | xargs -0 command
...