Удалить путь из вывода команды find

Вопрос или проблема

У меня есть скрипт bash для развертывания кода из бета-среды в производственную, но в настоящее время мне приходится вручную добавлять список файлов в текстовый файл, и иногда я что-то пропускаю. В основном, мой скрипт развертывания выполняет объединение/цикл, копируя файлы. (он также экспортирует/импортирует базу данных, но это не имеет значения..lol)

В любом случае, я хотел бы использовать команду find, чтобы сгенерировать список файлов, измененных за последние 14 дней. Проблема в том, что мне нужно удалить путь ./, чтобы скрипт развертывания работал.

Вот пример использования команды find:

find . -type f -mtime -14 > deploy.txt

Вот строка, которая выводит содержимое deploy.txt в моем скрипте развертывания:

for i in `cat deploy.txt`; do cp -i /home/user/beta/public_html/$i /home/user/public_html/$i; done

Есть идеи, как это сделать с помощью скриптов bash?

Спасибо!

Вы можете использовать опцию командной строки -printf с %f, чтобы напечатать только имя файла без какой-либо информации о каталоге

find . -type f -mtime -14 -printf '%f\n' > deploy.txt

либо вы можете использовать sed, чтобы просто удалить ./

find . -type f -mtime -14 | sed 's|^./||' >deploy.txt

./ должен быть безвредным. Большинство программ будут считать /foo/bar и /foo/./bar эквивалентными. Я понимаю, что это не выглядит очень красиво, но исходя из того, что вы написали, я не вижу причин, почему это могло бы привести к сбою вашего скрипта.

Если вы действительно хотите это удалить, sed вероятно, самый чистый способ:

find . -type d -mtime 14 | sed -e 's,^\./,,' > deploy.txt

Если вы находитесь на системе с GNU find (например, на большинстве систем Linux), вы можете сделать это одним выстрелом с find -printf:

find . -type d -mtime 14 -printf "%P\n" > deploy.txt

%P возвращает полный путь каждого найденного файла, за исключением пути, указанного в командной строке, до и включая первый слэш. Это сохранит любые подкаталоги в вашей структуре каталогов.

Решение “find -printf” не сработает на FreeBSD, потому что find не имеет такой опции. В этом случае поможет AWK. Он возвращает последнее имя ($NF), поэтому может работать на любой глубине.

find /usr/local/etc/rc.d -type f | awk -F/ '{print $NF}'

PS: взято из книги Д. Тансли “Программирование оболочек Linux и Unix”

Почему вы хотите удалить ./? Это допустимо иметь его в середине пути. Так что

cp -i dir1/./somefile dir2/./somefile

это совершенно нормально!

Но если вы хотите удалить имя каталога, используя find, вы можете использовать аргумент %P для -printf.

man find(1) говорит:

         %P     Имя файла с удаленным именем аргумента командной строки
                 под которым он был найден.

Пример

$ find other -maxdepth 1
other
other/CVS
other/bin
other/lib
other/doc
other/gdbinit
$ find other -maxdepth 1 -printf "%P\n"

CVS
bin
lib
doc
gdbinit

Обратите внимание на первую пустую строку! Если вы хотите избежать этого, используйте -mindepth 1

$ find other -mindepth 1 -maxdepth 1 -printf "%P\n"
CVS
bin
lib
doc
gdbinit

Ну, у вас есть несколько вариантов. Вы можете использовать опцию -printf в find, чтобы напечатать только имя файла, или вы можете использовать инструмент, такой как sed, чтобы просто удалить ./.

# просто напечатать имя файла, сломается, если у вас есть подкаталоги.
find . -mtime -14 -printf '%f\n'

# удалить ведущую ./
find .  -mtime -14 | sed -e 's/^\.\///'

Быстрое решение, если я правильно понимаю вопрос, – это использование cut на выводе команды find:

$> find . -type f -mtime -14 | cut -b 3- > deploy.txt

Это удалит первые два символа из каждой строки результата (в вашем случае ./). Возможно, это не лучшее решение, но оно работает в вашем случае.

sed идеально подходит для такого рода вещей.

$ find . -type f -mtime -14 | sed 's/^\.\///' > deploy.txt

Я не знаю, о каких именах файлов идет речь, но что-то с пробелами или переводами строк ставит под угрозу большинство решений здесь.

Мое предложение – использовать расширение параметров оболочки, чтобы удалить символы из каждого имени файла:

find . -mtime -14 -exec sh -c 'printf "${0#./}\n"' {} \; >deploy.txt

Если вам действительно нравятся каналы, вы можете использовать “безопасный” разделитель, такой как пустой, с xargs для приема каждого имени файла:

find . -mtime -14 -print0 | xargs -0 -n 1 sh -c 'printf "${0#./}\n"' >deploy.txt

Имейте в виду, что вывод этого НЕ разделен нулями, поэтому, хотя это может быть достаточно для визуальной проверки, ни одно из этих решений не создает файл deploy.txt, который безопасен для автоматизации, если вы не очень уверены в именах ваших исходных файлов.

Установите переменную окружения для папки, используйте это с find и снова удалите это имя из результатов с помощью perl (например). Это работает на Linux и BSD/macOS:

export mydir=~/Downloads; find "${mydir}"; perl -pe 's/^\Q$ENV{mydir}\E//'

Ответ или решение

Вопрос о том, как удалить путь из вывода команды find, достаточно актуален для многих разработчиков и администраторов, особенно когда речь идет о развертывании кода. В данной статье мы рассмотрим различные методы удаления префикса ./ из результатов выполнения команды find, чтобы упростить процесс развертывания.

Задача

Ваша задача заключается в том, чтобы сгенерировать список файлов, измененных за последние 14 дней, с помощью команды find и сохранить этот список в текстовый файл deploy.txt. Однако необходимо удалить ./ из начала каждого имени файла, чтобы ваш скрипт мог корректно обрабатывать эту информацию.

Решения

  1. Использование -printf:
    Если вы используете GNU find, то наиболее элегантным решением будет использование опции -printf с форматированием %P, которое исключает указанный путь:

    find . -type f -mtime -14 -printf "%P\n" > deploy.txt

    Данная команда сохранит имена файлов, убирая префикс пути.

  2. Использование sed:
    Альтернативой будет использование утилиты sed. Она отлично подходит для текстовой обработки и позволяет вам удалять ненужные символы:

    find . -type f -mtime -14 | sed 's|^\./||' > deploy.txt

    Этот метод работает за счет поиска строк, начинающихся с ./, и замены их на пустую строку.

  3. Использование cut:
    Простой метод — использование команды cut для обрезки первых двух символов:

    find . -type f -mtime -14 | cut -b 3- > deploy.txt

    Данный подход будет работать, однако не так элегантно, как предыдущие варианты.

  4. Использование awk:
    Если среда не поддерживает -printf, можно использовать awk:

    find . -type f -mtime -14 | awk -F/ '{print $NF}' > deploy.txt

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

  5. Параметрическая экспансия оболочки:
    Еще один более безопасный метод — это применение параметрической экспансии оболочки:

    find . -mtime -14 -exec sh -c 'printf "${0#./}\n"' {} \; > deploy.txt

    Этот подход также гарантирует, что обработка произведется правильно, даже в случае наличия пробелов.

Примеры использования в вашем скрипте

Если вы уже используете цикл for для копирования файлов из одной директории в другую, пример будет выглядеть следующим образом:

for i in $(cat deploy.txt); do 
    cp -i /home/user/beta/public_html/$i /home/user/public_html/$i
done

Заключение

На основании вышеописанных методов, вы можете выбрать наиболее подходящий для своих нужд способ удаления пути из вывода команды find. Если ваша среда поддерживает GNU утилиты, выбирайте -printf, так как это наиболее лаконичное и эффективное решение. Если нет — утилиты sed или awk также продемонстрировали свою эффективность и могут быть использованы без значительных усилий.

Надеюсь, эта информация окажется полезной для вашего процесса развертывания. Проектируйте свои скрипты так, чтобы они были не только функциональны, но и оставляли за собой чистый и понятный код!

Оцените материал
Добавить комментарий

Капча загружается...