LINUX.ORG.RU
решено ФорумAdmin

Немного пое..bashим в воскресенье

 , , ,


0

1

Всем доброго дня!

#!/bin/bash

shopt -s globstar

for f in **/test1/*

do

$f/script.sh

done

Что делает код выше всем понятно, а вот как сделать такое же, но без магии globstar?

Я чёто помыкался с


find ... exec

, но ничего пока не придумал.

★★★★★

Последнее исправление: Twissel (всего исправлений: 3)

Я не понял, что делает твой код. Ты же не используешь переменную $f :)

Что-то такое?

find ./test1/ -type f -name "script.sh" -exec ./'{}' \;

shell-script ★★★★★
()
Последнее исправление: shell-script (всего исправлений: 2)
Ответ на: комментарий от shell-script

Код делает ровно то, что ты написал :-)

Задача выполнить скрипт script.sh в каждом подкаталоге каталога test1, ты всё правильно написал.

И твой вариант быстрее.

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от Twissel

Код делает ровно то, что ты написал :-)

Нет, твой код не может делать ровно то, что он написал. Твой код делает одно и то же test1/**/script.sh неизвестное количество раз. Во что это раскрывается знать не могу, но уж точно не в вызов нескольких разных script.sh подряд.

t184256 ★★★★★
()
Ответ на: комментарий от Valar

Если необходимо, нужно закавычить переменные внутри bash -c.

Valar
()
Ответ на: комментарий от t184256

Взято отсюда, тогда вопрос во что же раскрываются 2 звёздочки?

Чуть позже проверю.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Valar

Да, но сильно длинно, глаза режет :-)

По сути, оно.

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от shell-script

Ты же не используешь переменную $f :)

Дошло.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

Так или иначе, версия, «на звёздочках», ожидаемо, медленнее find+exec

Это потому, что а) ваш скрипт внешний и каждый раз bash выполняет exec дугого bash даже если скрипты почти одинаковы и б) вам хватает логики find. Если одно из этих пунктов бы не выполнялось, то будет наоборот.

vodz ★★★★★
()
Ответ на: комментарий от Valar

Хотя да, виноват - это тоже хороший вариант.

Путь к скрипту мне нужен, куда ж без него :-)

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

А в этом варианте можно делать cd в каталог выполняемого скрипта?

Да, надо дополнить вызовом realpath, чтобы цикл получал аргументы с абсолютным путём, тогда путь всегда будет верный.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Мне интересно другое, почему в этом варианте Немного пое..bashим в воскресенье (комментарий) порядок обхода каталогов произвольный (случайный?), а при использовании функции scan алфавитный?

Или мне показалось? :-)

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

Мне интересно другое, почему в этом варианте Немного пое..bashим в воскресенье (комментарий) порядок обхода каталогов произвольный (случайный?), а при использовании функции scan алфавитный?

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

vodz ★★★★★
()
Ответ на: комментарий от Valar

костыли такие костыли…

       -execdir command {} 
              Like  -exec,  but  the  specified  command is run from the subdirectory containing the matched file
aol ★★★★★
()
Ответ на: комментарий от Twissel

Нужно указывать полный путь через realpath

Twissel ★★★★★
() автор топика
Ответ на: комментарий от vodz
for i in ./* ; do
  if [ -d "$i" ]; then
     scan "$i"

  fi
done

Ещё интересный момент, если таким образом обходить каталоги верхнего уровня функцией scan, мы из рекурсии обратно в цикл for не вернёмся. Ибо теряем управление :-)

Это можно как-то побороть, просто интересно.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

если таким образом обходить каталоги

Если бы вы умели в программирование, вы бы не делали таких ошибок, как ./* вместо «$scan_arg/»* и понимали что такое рекурсия, куда что выходит и прочее управление. bash тут дело десятое.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Рекурсия - когда функция вызывает саму себя заданное количество раз.

В нашем случае, в простейшем варианте, это количество подкаталогов со скриптом script.sh в каталоге, который передан функции scan как аргумент

вы бы не делали таких ошибок, как ./* вместо «$scan_arg/»*

Вот тут не понял, можно пример как правильно :-)

P.S. А вот про передачу управления по завершению рекурсии и в какую точку оно будет передано, я бы тоже послушал.

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от Twissel

Рекурсия - когда функция вызывает саму себя заданное количество раз.

Нет. Если известно количество раз, то цикл более производителен и меньше ест ресурсов, чем рекурсия.

Вот тут не понял, можно пример как правильно :-)

Я дал правильный пример в первом моём сообщении в этой теме. Вы просто теперь заменили каталог test1 на текущий каталог — точку.

P.S. А вот про передачу управления по завершению рекурсии

Не надо валить всё в кучу. Под завершением рекурсии понимают условие при котором не будет больше рекурсивных вызовов. Передача управления никуда не теряется, то что вызов рекурсивный означает, что в стеке вызова один и тот же адрес и больше ничего, с точки зрения программы/процессора рекурсивная функция ничем от обычной не отличается.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Нет. Если известно количество раз, то цикл более производителен и меньше ест ресурсов, чем рекурсия.

Под заданным количеством рекурсивных вызовов я не подразумевал, что оно известно заранее, я имел ввиду, что оно ограниченно некоторой величиной.

По понятным причинам.

Но это уже так, ремарка для порядка :-)

Спасибо.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от vodz

Все-таки покажу свою глупость и приведу полный код

#!/bin/bash

scan() {
       local p
        for p in  $(realpath "$1/"*); do
                [[ -L "$p" ]] && continuie
                if [[ -d "$p" ]]; then
                cd "$p"
                if [[ -x "gsync.sh" ]]; then
                /bin/bash -c "./gsync.sh"
                fi
                scan "$p"
                fi
        done
}

for i in ./* ; do
  if [ -d "$i" ]; then
     scan "$i"

  fi
done

Структура каталогов такова

/first/01/somedir{01..08}/gsync.sh

Родительских каталогов верхнего уровня всего 2 - first и second.

В каталоге first 8 подкаталогов, пронумерованных 01 от до 08. В каждом из этих нумерованных подкаталогов, в свою очередь, еще 8 каталогов, они и содержат скрипт gsync.sh.

Я попытался запустить скрипт выше из «родительского» каталога (например first), но скрипт gsync выполняется только для первой 8-ки вложенных каталогов из каталога верхнего уровня 01.

Почему и писал, что после того, как последний gsync-скрипт в первой 8-ке отработал, нам нужно как-то вернуться в оригинальный скрипт.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от vodz

В общем и целом, это непринципиально, но имеет место быть.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от vodz

Ничто не мешает оригинальную функцию scan натравить на родительский каталог first.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

Почему и писал, что после того, как последний gsync-скрипт в первой 8-ке отработал,

Никого не волнуют ваши путанные трудности, пишите явно и понятно, что вам конкретно не понятно. Из всего я понял так:

scan() {
        local p
        for p in "$1/"* ; do
                [[ -L "$p" ]] && continue
                if [[ -d "$p" ]]; then
                        cd "$p"
                        if /bin/bash "./gsync.sh"; then
                                return 1
                        else
                                if ! scan "$p" 1; then
                                        [[ $2 -ne 0 ]] && return 1
                                fi 
                        fi
                fi
        done
        return 0
}
scan "$(realpath .)" 0

vodz ★★★★★
()
Ответ на: комментарий от vodz

Да, обыкновенный return должен спасти гиганта мысли.

Попробую.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от vodz

сформулировал вопрос

Ограничен ли (в теории) уровень вложенности каталогов, которые обрабатываются функцией scan, пока будет найден script.sh ?

Twissel ★★★★★
() автор топика
Ответ на: сформулировал вопрос от Twissel

Ограничен ли (в теории) уровень вложенности каталогов, которые обрабатываются функцией scan, пока будет найден script.sh ?

Функция не держит открытыми каталоги, в отличии от простейшей рекурсивной реализации на языках низкого уровня, где это сделано так, что при считывании текущего имени идёт рекурсивный вызов если это имя будет каталогом, открывая всё более и более дескрипторов. Список элементов цикла интерпретатор держит в нестековой памяти, так что это может быть очень много. Сама интерпретация может использовать стек, но не много. Если у вас что-то чудовищное по вложенности каталогов, то можно развернуть рекурсию в массив, с одного конца берем по одному имени каталога, с другого добавляем все найденные каталоги в нём. Но это будет очень медленнее.

vodz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.