Преминаване през директории и действие върху файлове в bash скрипт

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

./проекти:

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 във вашия shebang, защото той напълно означава:

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

Второ, има някои типични модели на грешки: липсват интервали около променливите (напишете "$dir", за да се справите с имена на директории, съдържащи интервали), има фалшив $ във вашия for ред (напишете for dir in "$1"*) вместо това, редът set е неправилен (set е обвивка вграден се използва само за промяна на конфигурацията на обвивката, напр. 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 скриптове, за да откриете типични грешки и имат обратна връзка w.r.t. добри практики. Ако имате дистрибуция на 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