Подстановочный знак: возвратите исходный путь

Я пытаюсь переименовать каждый access.log.gz файл (примечание: точное имя файла, не "начинаясь" или "содержащий") найденный в /home/*/logs кому: date-access.log.gz в той же папке.

for file in /home/*/logs/access.log.gz
do
   mv -v "$file" /home/*/logs/old/`date +\%G-\%m-\%d`"-access.log.gz"
done

Конечно, я добираюсь /home/*/logs/2014-09-08-access.log.gz - No such file or directory. Как я могу звонить * пути назад? Каждый файл должен быть переименован и перемещен в/old/subdir исходной папки. Я попробовал

mv -v "$file" /home/`$1`/logs/old/`date +\%G-\%m-\%d`"-access.log.gz"

... но не работал.

1
задан 9 September 2014 в 00:09

3 ответа

Использовать find (Как может я использовать найти команду более эффективно?).

find /home/ -ipath */logs/access.log.gz

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

find /home/ -ipath */logs/access.log.gz -execdir mv "{}" "old/`date +\%G-\%m-\%d`-access.log.gz" \;

Функции find мы используем, вот:

  • -ipath шаблоны соответствий в найденных именах файлов. Вы могли также использовать -name если Вы знали наверняка существует только один access.log.gz файл в каждом подпути (-name access.log.gz).
  • -execdir выполняет данную команду на каждом найденном файле, от подкаталога, содержащего подобранный файл. Это эквивалентно выполнению cd туда, где каждый файл и затем выполнение команды там. В этом случае это сохраняет большую логику управления путем. Найденным файлом заменяют {}. Заметьте также, что "старый" дан как относительный путь (поскольку Вы сказали это old/ существует в logs/)
2
ответ дан 10 November 2019 в 19:22

Просто разделите и повторно соберитесь $file поскольку Вы выполняете итерации по файлам соответствия: ${file%/*} дает Вам $file со всем после последнего / удаленный, и ${file##*/} дает Вам $file со всем перед последним / удаленный; взятый вместе ${file%/*}/old/$date-${file##*/} даст Вам "новое" соответствие имени файла $file.

По-видимому, дата не изменится в ходе запущения Вашего скрипта, таким образом, не будет никакого смысла в вызове date для каждого файла; скорее сохраните дату в переменной однажды и затем используйте это во время цикла: date=$(date '+%G-%m-%d'). (Обратите внимание, что современные сценарии должны использовать $(...) вместо обратных галочек. Также отметьте это % не "специальный" символ и так не нуждается в заключении в кавычки или выходе, хотя как хорошую практику целая строка формата должна быть заключена в кавычки.)

Если у Вас есть новая версия Bash, можно избежать подоболочки полностью при помощи printf -v date '%(%G-%m-%d)T' -1 вместо этого.

Вы могли бы также найти полезным использовать shopt -s globstar так, чтобы можно было искать на произвольную глубину в каталогах, и shopt -s nullglob так, чтобы несопоставленный шарик (подстановочный знак) ни до "чего" не расширялся вместо исходного шаблона шарика.

При помещении их всех вместе мы добираемся:

shopt -s globstar nullglob
date=$( date '+%G-%m-%d' )
for file in /home/*/logs/**/access.log.gz
do
    target=${file%/*}/old/$date-${file##*/}
    mv -vi "$file" "$target"
done
1
ответ дан 10 November 2019 в 19:22

Если Вы имеете , установленный zsh, использует zmv . В сценарии:

#!/bin/zsh
autoload zmv
zmv '/home/*/logs/access.log.gz' '$f:h/`date +\%G-\%m-\%d`-$f:t'

На zsh командной строке, помещенной autoload zmv в Вашем ~/.zshrc и выполненный, что последняя строка в командной строке.

0
ответ дан 10 November 2019 в 19:22

Другие вопросы по тегам:

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