У меня есть несколько открытых приложений. Выполнение wmctrl и передача по каналу вывода к awk перечисляют окно ID (исключая "липкие" окна) как это:
$ wmctrl -l | awk ' !/-1/ { print $1 } '
0x00a00018
0x04800005
0x04e00005
0x04400003
0x05000003
0x0540002b
0x05a00012
0x05800002
0x05c00003
$
Я могу отправить этот вывод в wmctrl для закрытия всех этих окон:
окна без содержания, которое должно быть сохранено и окна, которые не нуждаются в ответе, закроются, не спрашивая меня, но
окна, такие как те из редакторов с несохраненным содержанием или терминалами, выполняющими процесс, закроются "корректно": соответствующее приложение представит окно, разрешающее мне сохранить изменения или отменить изменения или сообщить мне о процессе, который это все еще выполняет.
Следующий сценарий, присвоенный подходящему ярлыку, работам:
#!/bin/bash
list=$(wmctrl -l | awk ' !/-1/ { print $1 } ')
for i in ${list[@]}
do
wmctrl -i -a $i
wmctrl -i -c $i
done
Я нашел что более простое (мне) for i in $list
также работы.
Там какая-либо причина состоит в том, чтобы предпочесть один по другому?
"липкий" и "корректно" условия от man wmctrl
.
В Вашем сценарии $list
совпадает с ${list[@]}
.
Последний является синтаксисом массива, но в Вашем сценарии это - нормальная переменная.
Поскольку у Вас нет пробела в Вашем wmctl
выходные параметры, Вам не нужны массив и использование $list
прекрасно подходит.
Если это был массив, $list
только был бы первый объект массива (=> item1
) и ${list[@]}
расширился бы на все объекты (=> item1 item2 item3
).
Но то, что Вы действительно хотели, если это на самом деле был массив, "${list[@]}"
(с кавычками), который расширяется на "item1" "item2" "item3"
, таким образом, это не дросселировало бы на пробеле.
A while
цикл часто является лучшим соответствием, чем a for
цикл для обработки вывода команды, разрешения Вас к производственным линейкам непосредственно вместо того, чтобы хранить их в списке или массиве.
В этом случае это позволяет Вам избегать awk
команда в целом:
wmctrl -l | while read -r id dt stuff; do
case $dt in
-1) continue
;;
*) echo wmctrl -i -a "$id"
echo wmctrl -i -c "$id"
;;
esac
done
Удалите echo
s, после того как Вы рады, что это делает правильную вещь.
Как отмечено в комментариях, xargs
другая опция - но это становится хитрым, когда Вы хотите сделать больше чем одну вещь с каждым arg
.
Оригинальное название спросило, "какой для цикла лучше".
Для меня лучший метод является самым быстрым. Для обнаружения предварительно ожидают time
управляйте к своему сценарию или функции. Некоторые примеры:
$ time du -s
real 0m0.002s
user 0m0.003s
sys 0m0.000s
$ time ls
real 0m0.004s
user 0m0.000s
sys 0m0.004s
Важно сбросить кэшируемые буферные тесты промежутка хотя:
Если два цикла будут о том же в скорости, то я выберу тот с лучшей удобочитаемостью.
Объем этого вопроса, делает скорость не важной, хотя, потому что большая часть времени проведена, ожидая ввода данных пользователем и существует только максимум 10 окон, открытых для большинства людей.
Другие ответы фокусируются на перезаписи сценария, таким образом, я дам свою ценность за два цента также.
Строка:
list=$(wmctrl -l | awk ' !/-1/ { print $1 } ')
list
является универсальным и не описательнымТаким образом, я использовал бы:
Windows=( $(wmctrl -l | awk ' !/-1/ { print $1 } ') )
Строка:
wmctrl -i -a $i
-i
и -a
может быть объединен в -ia
.$i
является неописательным, я использовал бы $Window
вместо этого.Существует два способа записать более короткому больше читаемого сценария, сначала с массивом:
#!/bin/bash
Windows=( $(wmctrl -l | awk ' !/-1/ { print $1 } ' ) )
for Window in "${Windows[@]}" ; do wmctrl -ia $Window -c $Window ; done
второй без массива:
#!/bin/bash
Windows=$(wmctrl -l | awk ' !/-1/ { print $1 } ' )
for Window in $Windows ; do wmctrl -ia $Window -c $Window ; done
Я предпочитаю метод массива, потому что я пытаюсь узнать больше о них и хотеть использовать их как можно больше. Выбор является Вашим как бы то ни было.
Можно справиться без массива. Установка IFS к новой строке позволит for
к строкам цикла Вы можете затем unset
IFS в цикле, не влияя на сам цикл.
#!/bin/bash
IFS=$'\n'
for i in $(wmctrl -l); do
unset IFS
set -- $i
(($2 > -1)) && wmctrl -i -a $1 -c $1
done
(сброс позиционных параметров является аккуратным приемом для разделения строки в к полям).
если необходимо использовать массив, можно использовать mapfile и использовать в своих интересах функцию обратного вызова для создания чего-то подобного циклу. Для маленького набора повторений это может быть преимущество для использования более простого вызова функции.
mapfile -c 1 -C 'f(){ set -- $@; (($3 >= 0)) && wmctrl -i -a $2 -c $2; }; f' -t < <(wmctrl -l)
(долгая версия):
#!/bin/bash
f(){
set -- $@
if (($3 > -1)); then
wmctrl -i -a $2 -c $2
fi
}
mapfile -c 1 -C f -t < <(wmctrl -l)