LinuxForum.Fans
Тема

Область видимости переменных в bash

Автор: trivium 25 сообщений 6277 просмотров
#315504

Всем привет.
Есть bash скрипт, в котором обрабатываю файлы в ffmpeg и надо в цикле запомнить название предыдущего файла.
Пишу:

text
#!/bin/bash
PREV_PATH_FILE=""
...
while true
здесь выборка из базы
do
...
PREV_PATH_FILE="path_to_file"
#и если где-то здесь обратиться к переменной, то в ней будет значение
...
done

Но если обратиться к переменной при новой итерации цикла, то в ней будет пусто. Как можно запомнить это значение и записать в глобальную переменную, т.к. я так понял он создаёт локальную и пишет в неё, а при новой итерации использует глобальную?

#315506

УМВР:
[console]alexander@goblin /tmp $ cat ./1.sh
#!/bin/bash
prv=""

echo -e '1\n2\n3' | while read i; do
echo $i:$prv
prv=$i
done
alexander@goblin /tmp $ ./1.sh
1:
2:1
3:2[/console]

#315507
Fat-Zer написал:
УМВР:
[console]alexander@goblin /tmp $ cat ./1.sh
#!/bin/bash
prv=""

echo -e '1\n2\n3' | while read i; do
echo $i:$prv
prv=$i
done
alexander@goblin /tmp $ ./1.sh
1:
2:1
3:2[/console]

А зачем while read, echo и т.д.?
Мне просто надо получить значение переменной в следующей итерации.

#315508

По-моему, нужно как-то так цикл делать:

text
while read i; do
# что-то делаем
echo $i # отладочный вывод
done < list_of_files
#315510
yars написал:
По-моему, нужно как-то так цикл делать:
text
while read i; do
# что-то делаем
done < list_of_files

Это вечный цикл, он должен постоянно работать и файлы с базы брать новые.

#315511
"trivium" написал:
Это вечный цикл

Покажите как вы выбираете файлы из базы.

#315512
"trivium⇓" написал:
А зачем while read, echo и т.д.?

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

#315513
yars написал:
[quote="trivium"]Это вечный цикл

Покажите как вы выбираете файлы из базы.[/quote]

text
PREV_FILE_PATH=""
while true
do 
    mysql -h$DB_HOST -u $DB_USER -p$DB_PASS $DB_NAME ...;
    do
                PREV_FILE_PATH="FILE_PATH"
done
sleep 3s
done

И на новой итерации уже нет ничего в PREV_FILE_PATH

#315514
Fat-Zer написал:
[quote="trivium⇓"]А зачем while read, echo и т.д.?

это просто для того, чтобы на ввод что-то пихнуть... чтобы значения в цикле менялись...
суть в том что в bash'е область видимости обычной (не локальной или экспортированной) переменной равна скрипту...
проблема где-то в другом месте...[/quote]
Нашёл, что вроде для циклов создаются новые процессы, из которых видны только переданные переменные, а то, что они меняли выходит нельзя получить никак?

#315515
"trivium" написал:
Нашёл, что вроде для циклов создаются новые процессы,

Это где? Переменные, объявленные в функции извне недоступны, переменные, объявленные в скрипте доступны из любой части скрипта, в том числе и в функции. У вас речи о функциях не идет, что-то не так с запросом к БД. Смотрите логи мускуля.

#315516
yars написал:
[quote="trivium"]Нашёл, что вроде для циклов создаются новые процессы,

Это где? Переменные, объявленные в функции извне недоступны, переменные, объявленные в скрипте доступны из любой части скрипта, в том числе и в функции. У вас речи о функциях не идет, что-то не так с запросом к БД. Смотрите логи мускуля.[/quote]
Нет, с БД всё нормально. В цикле видны все переменные, но если поменять значение этих переменных в цикле, то они теряются, и на следующей итерации значение опять старое. Нашёл тут: http://asplinux.net/node/2981

#315521
"yars⇓" написал:
Переменные, объявленные в функции извне недоступны

ЛПП... доступны, если их не объявить с local.
[console]alexander@goblin /tmp $ q=0; echo $q
0
alexander@goblin /tmp $ foo() { q=2; }; foo; echo $q
2
alexander@goblin /tmp $ foo() { local q=4; }; foo; echo $q
2
[/console]

"trivium⇓" написал:
do
PREV_FILE_PATH="FILE_PATH"
done

а это что за галиматья?

#315522
Fat-Zer написал:
[quote="yars⇓"]Переменные, объявленные в функции извне недоступны

ЛПП... доступны, если их не объявить с local.
[console]alexander@goblin /tmp $ q=0; echo $q
0
alexander@goblin /tmp $ foo() { q=2; }; foo; echo $q
2
alexander@goblin /tmp $ foo() { local q=4; }; foo; echo $q
2
[/console]

"trivium⇓" написал:
do
PREV_FILE_PATH="FILE_PATH"
done

а это что за галиматья?

"trivium⇓" написал:
Нашёл, что вроде для циклов создаются новые процессы, из которых видны только переданные переменные, а то, что они меняли выходит нельзя получить никак?

возможно это относилось к другому языку...[/quote]
Какая ещё галиматья? Это присвоение значений как бы. И ссылку я привёл. Это про bash.

#315523
"trivium⇓" написал:
Какая ещё галиматья?

галиматья потому что do/done ни к чему не относятся...

"trivium⇓" написал:
Это присвоение значений как бы. И ссылку я привёл. Это про bash.

да... давно страницу не обновлял... только потом увидел...
там про особенность работы трубы написано... таких скользких мест в баше много....

#315535
Fat-Zer написал:
[quote="trivium⇓"]Какая ещё галиматья?

галиматья потому что do/done ни к чему не относятся...

"trivium⇓" написал:
Это присвоение значений как бы. И ссылку я привёл. Это про bash.

да... давно страницу не обновлял... только потом увидел...
там про особенность работы трубы написано... таких скользких мест в баше много....[/quote]
do/done относится вроде как к MySQL выборке. Но не в этом суть. А в том как сделать, чтобы можно было менять внутри цикла.

#315543
"trivium⇓" написал:
do/done относится вроде как к MySQL выборке. Но не в этом суть. А в том как сделать, чтобы можно было менять внутри цикла.

ладно... слабое телепатическое поле подсказывает, что из мускуля труба вела в while, который куда-то делся из поста...
ну дык тогда по ссылке всё написано...

text
while read line; 
   # do_something
done < <(mysql …)

или другие решения в зависимости от шела и т.п.

ЗЫ: подробное описание что и почему и какие варианты тут

#315585
Fat-Zer написал:
[quote="trivium⇓"]do/done относится вроде как к MySQL выборке. Но не в этом суть. А в том как сделать, чтобы можно было менять внутри цикла.

ладно... слабое телепатическое поле подсказывает, что из мускуля труба вела в while, который куда-то делся из поста...
ну дык тогда по ссылке всё написано...

text
while read line; 
   # do_something
done < <(mysql …)

или другие решения в зависимости от шела и т.п.

ЗЫ: подробное описание что и почему и какие варианты тут[/quote]
Да, я читал про subshell и пробовал указывать в конце пути, но я так понял не в этом дело, а во внутренней выборке в цикле. В общем вот примерно такой, скрипт, там на вообще ещё одна выборка внутри идёт и эту переменную надо менять, но хотя бы в это понять что не так:

text
#!/bin/bash
while true
do
    echo "$PREV_FILE_PATH"

mysql -h$DB_HOST -u $DB_USER -p$DB_PASS $DB_NAME ... while read ...; do

PREV_FILE_PATH="777" done

done

А вывод идёт такой:

127
127
127

Но если перенести PREV_FILE_PATH="777" сразу перед последним done, то выводит так:

text
127
777
777
777
#315606

Это из-за конвеера. Если написать так:

text
#!/bin/bash
while true
do
    echo "$PREV_FILE_PATH"

PREV_FILE_PATH=`mysql -h$DB_HOST -u $DB_USER -p$DB_PASS $DB_NAME ... while read ...; do

echo "777" done`

done

Но у меня в цикле идёт куча вывода текста. Можно как-то всё таки это починить?

#315609
"trivium⇓" написал:
В общем вот примерно такой, скрипт, там на вообще ещё одна выборка внутри идёт и эту переменную надо менять, но хотя бы в это понять что не так:

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

#315613
Fat-Zer написал:
[quote="trivium⇓"] В общем вот примерно такой, скрипт, там на вообще ещё одна выборка внутри идёт и эту переменную надо менять, но хотя бы в это понять что не так:

давай полный код, по рассказам не понятно уже что-где...[/quote]
Так вот же код:

text
#!/bin/bash
while true
do
    echo "$PREV_FILE_PATH"

PREV_FILE_PATH=`mysql -h$DB_HOST -u $DB_USER -p$DB_PASS $DB_NAME ... while read ...; do

echo "777" done`

done

По ходу придётся в файл писать и читать оттуда...

Войдите или зарегистрируйтесь, чтобы ответить.