Перебирайте каталоги и работайте с файлами в сценарии bash

У меня есть сценарий /home/user/me/my_script.sh, который должен перебирать несколько каталогов и обрабатывать файлы. Мой текущий рабочий каталог / home / user / me. Вызов ls -R дает:

./projects:

dir1 dir2 dir3

./projects/dir1:

image1.ntf points2.csv image1.img image1.hdr

./projects/dir2:

image2.ntf points2.csv image2.img image2.hdr

./projects/dir3:

image3.ntf points3.csv image3.img image3.hdr

У меня есть такой сценарий:

#! /bin/bash -f
for $dir in $1*
do
  echo $dir
  set cmd = `/home/tools/tool.sh -i $dir/*.ntf -flag1 -flag2 -flag3 opt3`
  $cmd
done

Вот как он запускается (из cwd / home / user / me) и результат:

bash-4.1$ ./myscript.sh projects/
projects/*
bash-4.1$

Это не ожидаемый результат. Ожидаемый результат:

bash-4.1$ ./myscript.sh projects/
projects/dir1
[output from tool.sh]
projects/dir2
[output from tool.sh]
projects/dir3
[output from tool.sh]
bash-4.1$

Что должно произойти, так это то, что сценарий должен перейти в первый каталог, найти файл * .ntf и передать его в tool.sh. В этот момент я бы начал видеть результат работы этого инструмента. Я запустил инструмент для одного файла:

bash-4.1$ /home/tools/tool.sh -i /home/user/me/projects/dir1/image1.ntf -flag1 -flag2 -flag3 opt3
[expected output from tool. lengthy.]
bash-4.1$

Я пробовал найти здесь синтаксис: Как перебирать каталоги в Linux? и здесь: Цикл по каталогам в Bash

for $dir in /$1*/
do ...

Результат:

bash-4.1$ ./myscript.sh projects/
/projects/*/

И:

for $dir in $1/*
do ...

Результат:

bash-4.1$ ./myscript.sh projects
projects/*

Я не уверен, сколько еще итераций подстановочного знака и косой черты я смогу придумать. Какой правильный синтаксис?


person SatelliteEyes    schedule 28.06.2018    source источник
comment
Является ли длинный ожидаемый результат tool.sh набором команд или каким-то другим результатом?   -  person ghoti    schedule 28.06.2018
comment
Это текстовый вывод о том, где инструмент находится в процессе. Он берет файл * .ntf и выполняет несколько вычислений с изображением для создания откалиброванного изображения. Обработка большого изображения может занять несколько минут, поэтому этот вывод позволяет пользователю информировать пользователя о ходе выполнения.   -  person SatelliteEyes    schedule 28.06.2018
comment
Итак ... похоже, вы пытаетесь установить переменную $cmd для вывода сценария, а затем запускаете этот вывод, как если бы это была команда. Каковы ваши намерения с этой переменной? Почему бы просто не запустить инструмент напрямую? (Не стесняйтесь отвечать, уточняя в своем вопросе, а не в комментариях.)   -  person ghoti    schedule 28.06.2018
comment
Кстати, shellcheck.net автоматически обнаружит хотя бы часть проблем.   -  person Charles Duffy    schedule 28.06.2018


Ответы (1)


Во-первых, вы должны удалить флаг -f в своем шебанге, потому что это означает:

$ man bash
[…]
        -f      Disable pathname expansion.

Во-вторых, есть несколько типичных шаблонов ошибок: отсутствуют пробелы вокруг переменных (напишите "$dir", чтобы справиться с именами каталогов, содержащими пробелы), вместо этого в вашей строке for есть ложный $ (напишите for dir in "$1"*), строка set неверна (set - это оболочка builtin используется только для изменения конфигурации оболочки, например set -x), согласно вашему ответу на вопрос @ ghoti кажется, что строка $cmd не нужна. Кроме того, синтаксис обратных кавычек устарел, и его можно было бы заменить на cmd=$(/home/tools/tool.sh -i "$dir"/*.ntf -flag1 -flag2 -flag3 opt3).

Это приведет к следующему сценарию:

#!/bin/bash
for dir in "$1"*
do
  [[ -d "$dir" ]] || continue  # only consider existing folders
  printf "%s=%q\n" dir "$dir"
  /home/tools/tool.sh -i "$dir"/*.ntf -flag1 -flag2 -flag3 opt3
done

Кроме того, я бы рекомендовал всегда запускать статический анализатор ShellCheck в ваших сценариях Bash, чтобы обнаруживать типичные ошибки и отзывы о передовой опыт. Если у вас есть дистрибутив Linux, его следует установить с помощью стандартного диспетчера пакетов. .

person ErikMD    schedule 28.06.2018
comment
"$1"*/, если вы хотите, чтобы в качестве результатов поиска использовались только каталоги. В противном случае файлы тоже могут появиться. В качестве альтернативы можно использовать [[ -d "$dir" ]] || continue внутри цикла - это также исправит случай, когда каталоги не существуют, так что вы получите строку с возвращенным литералом * без необходимости nullglob. - person Charles Duffy; 28.06.2018
comment
Действительно, @CharlesDuffy (спасибо!) Я только что добавил ваше второе предложение в свой ответ. - person ErikMD; 28.06.2018
comment
... о, может, стоит поставить \n в конце строки формата printf. (Похоже, что я написал кое-что - извиняюсь, если это мысли исходило от меня!) - person Charles Duffy; 28.06.2018
comment
Спасибо, это работает! Я буду широко использовать ShellCheck в будущем. Я часто создаю новые сценарии из сценариев других людей, поэтому старые практики распространяются, когда этого не следует делать. - person SatelliteEyes; 28.06.2018