4

У меня есть следующая строка кода, которую я использую для обновления моей персональной переменной даты в моих проектах до текущей текущей даты. Эта линия работает в терминале Ubuntu, но терминал Mac, похоже, далеко позади. К сожалению, я скопировал этот фрагмент с какого-то сайта, поэтому я не уверен, как именно он работает. Предложения?

grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" * |
    grep -v .git | xargs -i@ sed -i "s/\[DATE\]/${today}/g" @

5 ответов5

6

В BSD xargs нет -i , и эта опция в GNU xargs в любом случае устарела (когда было написано это руководство? 1995?). Вместо этого используйте -I .

4

Как это работает

  1. Создайте список имен файлов:

    grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" *
    

    Рекурсивно ищите (-r) файлы и перечисляйте (-l) имена тех, где содержимое файла соответствует регистронезависимому (-i) регулярному выражению '[DATE]' (что означает, что файл содержит любой из 8 символов "AaDdEeTt"); исключить имена revar.sh и README.md, и

  2. Удалите все имена файлов из списка, которые содержат символ, за которым следует "git" (поэтому имя файла "агитатор" будет удалено):

    grep -v .git
    
  3. Обрабатывайте файлы по одному, применяя к файлу определенный скрипт sed. В современных обозначениях (POSIX - и MacOS X, и Linux, AIX, HP-UX, Solaris и т.д.):

    xargs -I@ sed -i "s/\[DATE\]/${today}/g" @
    

    Параметр '-i' для 'sed' означает перезапись входных файлов после обработки. Это расширение GNU и BSD для sed, не указанное в стандарте POSIX.

Что в этом неправдоподобного

Этот сценарий можно критиковать на многих уровнях.

  • Первая строка поиска неверна; он должен иметь обратную косую черту перед скобками; большинство файлов содержат хотя бы одну из букв «dateDATE».
  • Второй grep предположительно предназначен для удаления чего-либо из каталогов .git и нуждается в исправлении.
  • Команда «sed» не учитывает регистр при поиске «[DATE]», в отличие от первого «grep».

Как это исправить

Итак, одна из двух альтернатив имеет смысл.

Или:

grep -ilr --exclude=revar.sh --exclude=README.md "\[DATE\]" * |
grep -v '\.git/' |
xargs sed -i "s/\[[Dd][Aa][Tt][Ee]\]/${today}/g"

Или же:

grep -lr --exclude=revar.sh --exclude=README.md "\[DATE\]" * |
grep -v '\.git/' |
xargs sed -i "s/\[DATE\]/${today}/g"

Как отметил Донал Феллоуз, в этом контексте нет необходимости использовать опцию «-i» или «-I» для «xargs».

Это полезно, даже когда исправлено?

Это просто оставляет меня озадаченным, насколько это полезно. В первый день все вхождения «[ДАТА]» сопоставляются с «2010-04-17»; что происходит на следующий день? Как вы снимаете карты с дат, прежде чем вносить в репозиторий git?

Тем не менее, по крайней мере, теперь вы знаете, что он делает и как он это делает.

3

Опция -i для xargs никогда не нужна, если место для замены находится в конце строки; это где имена файлов будут помещены в любом случае. И BSD xargs (что обеспечивает OSX) также не поддерживает эту опцию. Так что попробуйте это:

grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" * |
    grep -v .git | xargs sed -i "s/\[DATE\]/${today}/g"
1

Что касается флага -i sed в Mac OS X для редактирования файлов на месте, вы должны добавить пустую строку в качестве аргумента:

sed -i "" 's/regex/replace/g' file

sed -i "" 's/regex/'"${var}"'/g' file   # create sed expression using string concatenation
0

Используя расширение параметров Bash, вы также можете почти автоматически избежать проблем с форматированием sed:

# some basic Bash parameter expansion examples to play with
var='ddd/abc/ddd'
var="$(date)"
var=$'\\\n'

echo abc | sed 's/b/'"${var}"'/g'
echo abc | sed 's/b/'"${var//\//\\/}"'/g'

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