Как задать переменную в скрипте bash, чтоб она сохранялась при использование цикла?
Я практикуюсь в написании bash скриптов и у меня возникла проблема, при выполнение моего скрипта "/myscript.sh /firstpath/* /secondpath" все переменные базовые {1-9} переопределяются в цикле. У меня есть такой скрипт
#! /bin/bash
# Берёт путь из переменной №1 и копирует от туда все файлы по пути переменной №2 добавляя при этом в название дату и время создания файла
Dirend=${2}
echo ${1}
echo ${2}
for i in ${1}; do bname=$(basename $i);suf=$(ls -l $i | awk '{print $6,$7,$8}'| sed 's/ /_/g')| sed 's_/__'; cp ${i} ${Dirend}/${bname}_${suf}; done
В итоге я получаю такой ответ.
/home/test/firstpath/file#2.txt
/home/test/firstpath/file#1.txt
cp: failed to access '/home/test/firstpath/file#2.txt/file#1.txt_': Not a directory
Я относительно понял почему так происходит. По моему представлению просто переменные {1-9} являются ссылочными и переопределяются в цикле, но как это реализовать по другому информации не нашел пока что.
Ответы (1 шт):
для точности формулировок дальше параметрами я буду называть то, что указывается в команде при вызове скрипта, а аргументами то, что получает скрипт при выполнении. да, эти две сущности могут не совпадать, как в описанном в вопросе случае.
сначала про ошибки:
for i in ${1}; do ...; done— такой цикл отработает ноль (если параметров скрипту вообще не передавалось) либо один раз (только для первого из аргументов).- так как в каталоге
firstpathу вас находится несколько файлов/каталогов, то конструкцияfirstpath/*, переданная как параметр, будет преобразована в несколько аргументов, по одному аргументу на каждый файл/каталог, имя которого соответствует маскеfirstpath/*. соответственно, у вашего скрипта будет плавающее количество аргументов, и целевой каталог надо извлекать из списка аргументов именно как последний аргумент, а не просто как второй по порядку. - (завуалированная ошибка) не стоит парсить вывод программы
ls, запущенной с опцией-l: формат вывода там «плавающий», для чтения человеком. а для машинной обработки информацию из inode файла/каталога лучше получать программой stat.
теперь про исправление:
получить последний аргумент, переданный скрипту, можно разными способами. например (для программы bash версии >= 3.0):
last=${BASH_ARGV[0]}пройтись циклом по всем аргументам кроме последнего можно разными способами. например:
for i in "${@:1:$(($#-1))}"; do ...; doneпрограммой stat можно получить время модификации файла(-ов)/каталога(-ов) в виде количества секунд с начала эпохи:
$ stat -c '%Y' файлы каталоги ...преобразовать это значение в дату/время можно с помощью программы date:
$ date -d @1630581630 +"%F_%T" 2021-09-02_11:20:30