Как найти и заменить на egrep и sed на macOS? - PullRequest
0 голосов
/ 03 февраля 2019

Я хочу сопоставить шаблон в файле и заменить его.

Эта команда работает с egrep, xargs и sed:

egrep -lRZ "hello" . | xargs -0 -l sed -i -e 's/hello/world/g'

Проблема: Он не работает в MacOS, потому что xargs в MacOS не поддерживает аргумент -l.

xargs: illegal option -- l
usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]
             [-L number] [-n number [-x]] [-P maxprocs] [-s size]
             [utility [argument ...]]

Как это решается в MacOS?

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

Опций grep для рекурсивного поиска файлов лучше избегать - они просто загромождают ваши аргументы grep и делают ваши сценарии непереносимыми.Уже есть очень хороший инструмент, предназначенный для поиска файлов с очень очевидным именем.

Вы просто пытаетесь заменить hello на world во всех ваших файлах?Если это так, то это просто

find . -type f |
while IFS= read -r file; do
    sed 's/hello/world/g' "$file" > "tmp$$" &&
    mv "tmp$$" "$file"
done

. Это сработает в любой оболочке на любом компьютере UNIX, если в именах ваших файлов нет символов новой строки.Если вы не хотите изменять метки времени и т. Д. Для файлов, которые не содержат hello, используйте один из следующих способов:

find . -type f -exec grep -q 'hello' {} \; -print |
while IFS= read -r file; do
    sed 's/hello/world/g' "$file" > "tmp$$" &&
    mv "tmp$$" "$file"
done
0 голосов
/ 03 февраля 2019

На самом деле есть три несовместимости между утилитами GNU (Linux) и bsd (macOS).

  • Та, в которой вы получаете ошибкусообщение от bsd xargs не принимает параметр -l.Но -l эквивалентно -L, за исключением того, что -L требует аргумент, указывающий максимальное количество строк, которое должно быть передано за вызов команды, тогда как -l по умолчанию равен одной, если это не такуказано.Таким образом, вы можете просто заменить -l на -L1.-L понимается одинаково как в GNU, так и в bsd-версиях xargs, поэтому его использование переносимо между Linux и macOS.

    Но в данном конкретном случае есть еще одинЕще более простой вариант: sed прекрасно способен работать с несколькими файлами за вызов, поэтому нет причин ограничивать его одним файлом за вызов.Это даже будет немного быстрее, поскольку не нужно тратить так много времени на запуск новых процессов.Так что просто оставьте -l выключенным.

  • В версиях egrep (и других в семействе grep) GNU и BSD обе опции -Z, но они используютэто означает совершенно разные вещи.В GNU egrep -Z печатает нулевые байты (символы ASCII NUL) после каждого имени файла (соответствует тому, что ожидает xargs -0).Но с bsd egrep -Z эквивалентно zgrep - он обрабатывает свои входные файлы как zip-архивы и расширяет их перед поиском по их содержимому.

    К счастью, обе версии понимают --null для вызова нуля.разделители байтов, так что вы можете использовать это переносимо на обеих платформах.

  • В версиях GNU и bsd -i<suffix> понимается как «редактировать на месте, но сделать резервную копию и обратно».до оригинала с указанным суффиксом имени файла ".И для них обоих, если суффикс нулевой длины, он не сохраняет резервную копию.К сожалению, способ указания суффикса нулевой длины отличается и (насколько я смог найти) несовместимо несовместим.В частности, GNU требует, чтобы суффикс был непосредственно присоединен к -i (например, -i.bkp), поэтому достаточно указать только -i для указания режима на месте без резервного копирования.Но bsd позволяет передавать суффикс в качестве отдельного аргумента (например, -i .bkp), поэтому, если вы просто укажете -i сам по себе, он будет использовать любой следующий аргумент в качестве суффикса (например, sed -i -e 's/hello/world/g' будет использовать "-е "как суффикс).Чтобы указать режим на месте без резервного копирования, вам нужно следовать -i с явным пустым аргументом (например, sed -i '' -e 's/hello/world/g').Но если вы сделаете это с GNU sed, он попытается выполнить пустой аргумент в качестве своего скрипта, что не получится.

При всем этом, вот версия вашего MacOSкоманда:

egrep -lR --null "hello" . | xargs -0 sed -i '' -e 's/hello/world/g'

... которая будет почти работать в Linux - единственное отличие состоит в том, что вам нужно удалить аргумент '' для sed.Если вы хотите что-то полностью переносимое между Linux и macOS, вам нужно указать суффикс резервной копии (и присоединить его непосредственно к опции -i, как в -i.bkp).

...