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

BASH Цикл с двумя переменными

 , ,


0

1

Здравствуйте, уважаемые форумчане. Возникла трудность в решении (скорее всего) банальной задачи. Есть две папки с графическими файлами. Необходимо массово объединить изображение из одной папки с изображением из другой. Для решения этой задачи был написан скрипт:

#!/bin/bash
ls_png=$(ls 01/*.png)
echo "$ls_png" > png_list.txt
file_png="png_list.txt"
ls_gif=$(ls 02/*.gif)
echo "$ls_gif" > gif_list.txt
file_gif="gif_list.txt"
for png in `cat $file_png`; do
for gif in `cat $file_gif`; do
convert $png $gif -geometry 458x154+430+1276 -composite out/$png
done
exit

Но скрипт работает не корректно. В результате его выполнения получается, что первое изображение из папки «02» накладывается на все изображения из папки «01», а необходимо так, чтобы первое изображение из папки «02» оказалось поверх первого из папки «01», затем второе из папки «02» поверх второго из папки «01» и так далее. Помогите, пожалуйста, решить данную проблему. (Читал руководство https://rus-linux.net/nlib.php?name=/MyLDP/BOOKS/Bash-Guide-1.12-ru/bash-guide-index.html, разные, схожие по теме, посты на форумах, но гуманитарный склад ума и ограниченные временные сроки, не позволяют самостоятельно решить проблему)

РЕШЕНИЕ!

#!/bin/sh
PNG=()
GIF=()
for p in 01/*.png; do PNG+=("$p"); done
for p in 02/*.gif; do GIF+=("$p"); done
i=0
while [ -f "${PNG[$i]}" ]; do
  p="${PNG[$i]}"
  [ -f "${GIF[$i]}" ] && convert "$p" "${GIF[$i]}" -geometry 458x154+430+1276 -composite out/${p#01/}
  i=$[$i+1]
done
exit

Для тех, кто всегда запускал скрипты через

sh script_name.sh

правильно (в данном случае)

bash script_name.sh


Последнее исправление: l-irbis-l (всего исправлений: 2)

Ответ на: комментарий от papin-aziat

Количество одинаковое. Во втором каталоге лежать штрих-коды, в первом карточки товара. (Простите за вопрос, а как прикрепить изображение? Ссылкой на внешний ресурс?)

l-irbis-l
() автор топика

Дык зачем тебе второй цикл?

Я бы сделал тупо: каждый список в массив PNG, GIF и дальше цикл по индексу.

PNG=()
GIF=()
for p in 01/*.png; do PNG+=("$p"); done
for p in 02/*.gif; do GIF+=("$p"); done
i=0
while [ -f "${PNG[$i]}" ]; do
  p="${PNG[$i]}"
  [ -f "${GIF[$i]}" ] && convert "$p" "${GIF[$i]}" ....  out/${p#01/}
  i=$[$i+1]
done

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

Спасибо. После редактирования скрипта получилось следующее:

#!/bin/bash
ls_png=$(ls 01/*.png)
echo "$ls_png" > png_list.txt
file_png="png_list.txt"
ls_gif=$(ls 02/*.gif)
echo "$ls_gif" > gif_list.txt
file_gif="gif_list.txt"
exec 5< png_list.txt
exec 6< gif_list.txt
read line_png <&5
read line_gif <&6
convert $line_png $line_gif -geometry 458x154+430+1276 -composite out/000*.png
exit

Теперь создается лишь один файл. Последнее изображение из папки «02» объединяться с первым из папки «01».

l-irbis-l
() автор топика
Ответ на: комментарий от papin-aziat
l-irbis-l
() автор топика
Ответ на: комментарий от vel

Спасибо. Но мне не хватает знаний для реализации Вашего кода..

#!/bin/bash
PNG=()
GIF=()
for p in 01/*.png; do PNG+=("$p"); done
for p in 02/*.gif; do GIF+=("$p"); done
i=0
while [ -f "${PNG[$i]}" ]; do
  p="${PNG[$i]}"
  [ -f "${GIF[$i]}" ] && convert "$p" "${GIF[$i]}" -geometry 458x154+430+1276 -composite out/${p#01/}
  i=$[$i+1]
done
exit

Ошибка:

Compression_pdf.sh: 2: Syntax error: "(" unexpected
l-irbis-l
() автор топика
Ответ на: комментарий от l-irbis-l

либо явно запускать «bash скрипт», либо сделать скрипт исполняемый (chmod a+x скрипт) и запускать ./скрипт

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

Я б построил код вокруг паттерна совпадений в названиях файлов: 1.10.

Тогда можно в цикле for от 1 до 10 просто подставлять пути конвертору типа 01/*$f.png 02/*$f.gif

Например:

for f in `seq 1 10`; do
  ...

Это так, мысли вслух.

papin-aziat ★★★★★
()
Ответ на: комментарий от l-irbis-l

очень сложно мне даются даже такие простые решения

Знаю, тем более, когда ответы на них дают настоящие программисты. Поэтому нам, простым юзерам, надо упрощать, жертвуя эффективностью и универсальностью кода, насколько возможно.

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

У тебя, судя по названиям файлов, сочетающиеся файлы создаются с одинаковым порядковым номером от 1 и далее, после которого идёт расширение, — вот и паттерн!

(надо ещё порядковые номера привязать к префиксам, чтобы в подстановках не было путаницы: PNG к -, а гифки к 000)

Осталось сохранить количество файлов в переменную и использовать её в цикле.

#! /bin/bash

quantity=`ls -1 01/*.png | wc -l`

for f in `seq 1 $quantity`; do
  convert 01/*-$f.png 02/*000$f.gif -geometry 458x154+430+1276 -composite out/$f.png
done
papin-aziat ★★★★★
()
Последнее исправление: papin-aziat (всего исправлений: 2)

Для тех, кто всегда запускал скрипты через

sh script_name.sh

правильно (в данном случае)

bash script_name.sh

Правильно писать интерпретатор в начале скрипта, чтобы пользователь не заморачивался чем запускать. Конструкция называется shebang.

То есть вместо

#!/bin/sh

нужно писать

#!/bin/bash

и запускать скрипт вот так:

./script_name.sh

(ну или в каком каталоге он у тебя лежит)

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

То есть вместо
#!/bin/sh
нужно писать
#!/bin/bash

Ну такое себе нужно... Направление мысли в целом верное, но стиль изложения хромает. /bin/bash тоже может оказаться совсем не bash, зависит от дистра.

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

Ну такое себе нужно… Направление мысли в целом верное, но стиль изложения хромает.

Я всё-таки настаиваю на том, что пользователю - тому, для которого создаётся скрипт - именно нужно упрощать жизнь.

/bin/bash тоже может оказаться совсем не bash, зависит от дистра.

Вы путаете с /bin/sh - вот он может указывать на bash, csh, dash и др - всё то, что полностью реализует функционал sh, но предлагает что-то сверх того. Я пока не слышал, чтобы что-то, кроме оригинального bash, имплементоровало комбинацию POSIX + башизмы. Если вам о таком известно, поделитесь, пожалуйста, этим знанием с миром.

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

Это где такой идиотизм?

Точно не путаешь с /bin/sh → /bin/dash? Такое в Демьяне, но там bash — это bash.

А по поводу «нужно писать» за шебангом баш — да, это плохо. Но не потому что «кто-то вместо баша может положить zsh». А потому что на другом компьютере может не оказаться того, что ты ожидаешь.

Поэтому башизмы, дашизмы, зшизмы и т. п. можно использовать только когда ты не планируешь запускать скрипт где-то за пределами локалхоста.

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

Точно не путаешь с /bin/sh → /bin/dash?

Точно не путаю. С линками /bin/sh это уже хоть «привычное». А вот линк /bin/bash однажды оказался весьма непривычным. Точнее весьма удивил, но как обычно смирились и забили, есть так есть.

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

Не подскажешь в каком дистрибутиве такой маразм?

Уже не помню. Точнее не запоминаю, поматерился и забыл.

Или это у кого-то руками настроено так было?

А вот этот вопрос навел на мысль... Вроде у более чем одного дистра есть такая хрень их каробки при инстале.

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

это либо дистр типа болгеноса либо ты путаешь.. ну или этот dash совместим с bash.

вот наоборот бывало - sh это на самом деле bash. И некоторые скрипты делались с учётом этого (шапкодистры возможно такой симлинк делали, отсюда и относительная распространённость проблемы).
Лень было авторам две лишние букавы нопейсать.

теперь они есессно фейлятся так же как у ТСа.

mrjaggers
()
Ответ на: комментарий от vel

На всякий случай: массивы заполняются прекрасно и без цикла: PNG=(*.png); внутри квадратных скобок если массивы обычные, то есть не ассоциативные и так по умолчанию целочисленные выражения, потому доллар у $i не нужен, да и при приравнивании переменных, а не строковых выражений кавычки у v=${a} не нужны; $[expr] давно пытаются удалить из bash как устаревший синтаксис, он действительно мешает для сложных выражений с массивами. Но чтобы скрипт не глючил да и чтобы потренироваться в правильном программировании здесь таки ассоциативный массив напрашивается.

vodz ★★★★★
()

но гуманитарный склад ума и ограниченные временные сроки, не позволяют самостоятельно решить проблему

Гуманитарный склад ума не существует, а плохо спроектированные языки существуют. Bash — какашечный язык, по возможности избегайте его. На чём-нибудь нормальном (например на бабашке) задача решается элементарно:

user> (defn proper-convert [fg-dir bg-dir out-dir]
        (defn convert-images [foreground  background]
          (let [fg-name (fs/file foreground)
                bg-name (fs/file background)
                out-name (format  "%s/%s" out-dir (fs/file-name foreground))
                cmd (format "echo convert %s %s -geometry 458x154+430+1276 -composite %s"
                            fg-name bg-name out-name)]
            (-> cmd (process/shell {:out :string}) :out)))
        (map convert-images (fs/list-dir fg-dir) (fs/list-dir bg-dir)))
#'user/proper-convert
user> (proper-convert "/tmp/jpg" "/tmp/png" "/tmp/out")
("convert /tmp/jpg/4.jpg /tmp/png/4.png -geometry 458x154+430+1276 -composite /tmp/out/4.jpg\n"
 "convert /tmp/jpg/1.jpg /tmp/png/3.png -geometry 458x154+430+1276 -composite /tmp/out/1.jpg\n"
 "convert /tmp/jpg/5.jpg /tmp/png/5.png -geometry 458x154+430+1276 -composite /tmp/out/5.jpg\n"
 "convert /tmp/jpg/3.jpg /tmp/png/1.png -geometry 458x154+430+1276 -composite /tmp/out/3.jpg\n"
 "convert /tmp/jpg/2.jpg /tmp/png/2.png -geometry 458x154+430+1276 -composite /tmp/out/2.jpg\n")
user> 

Т.к. файлов у меня нет, я заменил convert на echo convert, чтобы продемонстрировать как оно будет работать.

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

А по поводу «нужно писать» за шебангом баш — да, это плохо. Но не потому что «кто-то вместо баша может положить zsh». А потому что на другом компьютере может не оказаться того, что ты ожидаешь.

В этом и суть. Если используешь башизмы, пиши что нужен bash. Если не используешь - пиши что sh.

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

Лень было авторам две лишние букавы нопейсать.

Это не лень, а тупость.

Если с /bin/sh ставят симлинк на иной интерпретатор, значит он может работать как замена sh. Если не умеет, но симлинк есть — см предложение выше. А если умеет, но видя в скрипте свои расширения не вываливается с ошибкой «sh такое не понимайт», а нормально хавает и отрабатывает — это баг.

А симлинкнуть с баша на даш, или с даша на зсш и т.п. здоровый человек не может.

mogwai ★★★★★
()