Почему этот скрипт выводит поврежденные файлы при автоматическом запуске с помощью crontab?

Сделайте это в VirtualBox. Просто установите Live CD iso в качестве загрузочного устройства и загрузите машину. У вас не должно возникнуть проблем.

1
30.03.2019, 00:37
1 ответ

Вероятно , потому что вы запускаете команды в конвейере.

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

Также обратите внимание, что на самом деле вы не используете аспект конвейера. Данные между командами не передаются.

Ваш сценарий лучше написать как

#!/bin/bash
#Creates index file.

find /var/www/html/uploads/Music/ -name '*.mp3' > /var/www/html/uploads/Music/songs.index

sed -i -e 's/\/var\/www\/html/\.\./g' /var/www/html/uploads/Music/songs.index

Здесь команда findзавершает выполнение до начала команды sed. Я также удалил команду sudoтак как она явно не нужна (если findможет писать в файл, то sedможет читать и изменять его безsudo).

Если вы обнаружите, что вам действительно нужно sudoдля записи songs.index, я бы посоветовал вам вместо этого запустить это задание cron в crontab, принадлежащем пользователю с разрешениями на запись в целевой каталог. /var/www/html/uploads/Music.

Конвейерным решением будет

#!/bin/sh
#Creates index file.

find /var/www/html/uploads/Music/ -name '*.mp3' |    
sed -e 's,^/var/www/html,..,' >/var/www/html/uploads/Music/songs.index

Здесь findзаписывает непосредственно в команду sed, а результат команды sedзаписывается в индексный файл. Передача данных (путей )из findв sedподдерживает синхронизацию двух процессов, и sedбудет ждать для findсоздания следующей строки ввода, прежде чем продолжить (и наоборот; findбудет ждать, пока sedобработает данные, прежде чем пытаться вывести больше данных ).

Я также упростил чтение команды sed, привязал регулярное выражение к началу строки и удалил ненужный флаг gв конце. Поскольку теперь он считывается из команды find,Я также удалил параметр -i(, строго говоря, параметр -eтакже можно было бы удалить ).

Еще я изменил строку #!. Вы не используете никакихbash-специфических функций, поэтому мы можем запустить скрипт с (возможно )более легкой -оболочкой.

Если вы хотите записать имена найденных файлов в индекс, заменив начальный /var/www/htmlна .., вы также можете сделать это непосредственно изfind:

#!/bin/sh
#Creates index file.

find /var/www/html/uploads/Music/ -type f -name '*.mp3' -exec sh -c '
    for pathname do
        printf "../%s\n" "${pathname#/var/www/html/}"
    done' sh {} + >/var/www/html/uploads/Music/songs.index

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

Модификация имени пути выполняется посредством подстановки параметра ${pathname#/var/www/html/}. Это удаляет строку /var/www/html/из начала значения в $pathname. Используемая строка формата printfгарантирует, что эта часть будет заменена на ../.

См. также

3
27.01.2020, 23:22

Теги

Похожие вопросы