Bash скрипт: проверка подстроки в строке не удалась

Вопрос или проблема

У меня есть скрипт, который открывает новое окно терминала, и я хочу переместить его в определенное положение на левом терминале с помощью xdotool.

После открытия терминала я выполняю

xdotool search --class gnome-term

и использую возвращенный идентификатор окна в командах xdotool windowsize и windowmove, чтобы изменить размер и положение нового окна терминала.

xdotool windowsize $WIN_ID 1978 407
xdotool windowmove $WIN_ID -26 702

Поскольку у меня запущено несколько терминалов, мне нужно определить, какому идентификатору окна WIN_ID соответствует только что созданное окно терминала.

В скрипте я выполняю следующую команду перед запуском нового терминала, чтобы получить список существующих идентификаторов WIN_ID.

for i in `xdotool search --class gnome-term`; do id_list="$id_list $i"; done

Пример содержимого $id_list:

65011713 65011722 65103242 65019818 65029314 65027106

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

for WID in `xdotool search --class gnome-term`; do if [[ ! $WID =~  $id_list ]]; then echo "Новый идентификатор окна = $WID"; fi; done

Когда я запускаю эту команду, вместо того чтобы получить только один (новый) идентификатор окна, я получаю все идентификаторы окон, связанные с классом gnome-terminal. Почему следующая команда не возвращает только WID, который не находится в id_list?

if [[ ! $WID =~  $id_list ]]; then ...

Скрипт:

...
...
# Создание списка идентификаторов окон для существующих окон gnome-terminal
for i in `xdotool search --class gnome-term`; do id_list="$id_list $i"; done

# Открытие нового окна терминала
gnome-terminal

# Получение идентификатора окна нового терминала
New_WID=`for WID in `xdotool search --class gnome-term`; do if [[ ! $WID =~  $id_list ]]; then echo $WID; fi; done`
...
...

Спасибо за ваше время и отзывы!

Текс

Если вы хотите найти идентификаторы окон, которые появились с момента последнего запуска xdotool search --class gnome-term, по сути, это операция вычитания списков.

Это можно сделать, например, с помощью:

#! /bin/zsh -
die() { print -ru2 -C1 -- "$@"; exit 1; }
before=( $(xdotool search --class gnome-term) )
gnome-terminal
after=( $(xdotool search --class gnome-term) )
new_wid=( ${after:|before} )
(( $#new_wid == 1 )) || die "$#new_wid найден новый window${new_wid[2]+s}"
xdotool windowsize $new_wid 1000 500 $new_wid 12582932 -26 702

Если вам нужно использовать bash, в котором нет оператора вычитания списков, вы можете использовать comm для этого:

#! /bin/bash -
println() { [ "$#" -eq 0 ] || printf '%s\n' "$@"; }
die() { println >&2 "$@"; exit 1; }
before=( $(xdotool search --class gnome-term | sort) )
gnome-terminal
after=( $(xdotool search --class gnome-term | sort) )
new_wid=( $(comm -13 <(println "${before[@]}") <(println "${after[@]}")) )
(( ${#new_wid[@]} == 1 )) ||
  die "${#new_wid[@]} новый window${new_wid[1]+s} найден"
xdotool windowsize "$new_wid" 1978 407 "$new_wid" 12582932 -26 702

Ответ или решение

Для решения проблемы с идентификацией нового идентификатора окна (WIN_ID) в вашем bash-скрипте, существует несколько моментов, на которые стоит обратить внимание. Давайте разберем ваш код и предложим его оптимизированную версию.

Проблематика

Ваша текущая попытка проверить, является ли WIN_ID новым, основана на использовании регулярного выражения с оператором =~. Однако переменная $id_list, содержащая список ранее открытых окон, не работает так, как вы ожидаете, когда используется в условии. Это связано с тем, что оператор =~ ожидает регулярное выражение, а не строку с пробелами.

Решение

Для более эффективного и надежного решения можно использовать встроенные возможности bash, такие как массивы, и команду comm для сравнения массивов, если вы не против использовать внешние команды.

Вот улучшенная версия вашего скрипта:

#!/bin/bash

# Функция для вывода ошибок и выхода из скрипта
die() { echo "$@" >&2; exit 1; }

# Сохраняем список идентификаторов окон до запуска нового терминала
before=($(xdotool search --class gnome-terminal | sort))

# Запускаем новый терминал
gnome-terminal &

# Ждем, пока новый терминал появится
sleep 1

# Сохраняем список идентификаторов окон после запуска
after=($(xdotool search --class gnome-terminal | sort))

# Находим новый идентификатор окна с помощью comm
new_wid=($(comm -13 <(printf '%s\n' "${before[@]}") <(printf '%s\n' "${after[@]}")))

# Проверяем, найден ли только один новый идентификатор окна
if [[ ${#new_wid[@]} -ne 1 ]]; then
  die "${#new_wid[@]} новых окна(ов) найдено. Ожидался один."
fi

# Изменяем размеры и позицию нового окна
xdotool windowsize "${new_wid[0]}" 1978 407
xdotool windowmove "${new_wid[0]}" -26 702

echo "Новое окно с ID=${new_wid[0]} успешно перемещено и изменено."

Основные изменения в скрипте:

  1. Использование массивов: Мы сохраняем список идентификаторов окон как массивы до и после запуска нового терминала. Это упрощает сравнение.

  2. Команда comm: Эта команда удобна для поиска различий между двумя отсортированными файлами или выводами, что облегчает задачу нахождения новых идентификаторов окон.

  3. Проверка количества новых окон: Мы явно проверяем количество найденных новых идентификаторов окон и выводим соответствующее сообщение об ошибке, если это не соответствует ожиданиям.

  4. Добавлен sleep 1: Это дает пару секунд, чтобы новый терминал успел появиться в системе, что может помочь избежать проблем с мгновенным извлечением идентификатора окна.

Теперь скрипт должен корректно находить и обрабатывать новые идентификаторы окон gnome-terminal. Пожалуйста, протестируйте его и сообщите, если возникнут дополнительные вопросы.

Оцените материал
Добавить комментарий

Капча загружается...