我打开了几个应用程序。正在运行控制端并将输出传输至awk列出窗口 ID(不包括“粘性”窗口),如下所示:
$ wmctrl -l | awk ' !/-1/ { print $1 } '
0x00a00018
0x04800005
0x04e00005
0x04400003
0x05000003
0x0540002b
0x05a00012
0x05800002
0x05c00003
$
我可以将此输出发送到控制端关闭所有这些窗口:
没有需要保存的内容的窗口和不需要响应的窗口将会关闭,而无需询问我,但
诸如未保存内容的编辑器窗口或正在运行进程的终端窗口将被“优雅地”关闭:相应的应用程序将显示一个窗口,允许我保存更改或放弃更改,或者通知我仍在运行的进程。
分配给合适快捷方式的以下脚本可以起作用:
#!/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
。
答案1
在您的脚本中$list
与 相同${list[@]}
。
后者是数组语法,但在您的脚本中它是一个普通变量。
由于您的输出项中没有空格wmctl
,因此您不需要数组,使用$list
就完全没问题。
如果它曾是一个数组,$list
只会是数组的第一个项(=> item1
)并且
${list[@]}
会扩展到所有项(=> item1 item2 item3
)。
但你真正想要的是曾是数组是"${list[@]}"
(带引号),其扩展到"item1" "item2" "item3"
,因此它不会被空格阻塞。
(读)
答案2
循环while
通常比循环更适合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
。
答案3
回答原标题
原标题问“什么类型的for循环比较好”。
对我来说,最好的方法就是最快的方法。要找出答案,请将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 } ') )
- 外部的 () 集合告诉 bash/shell 里面的所有内容都是由空格划定的数组元素。
- 我们正在谈论的是 Windows,所以它是一个描述性的数组名称。
- Windows 是复数,因此命名约定有助于识别它是一个数组。
以下行:
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
我更喜欢数组方法,因为我正在尝试更多地了解它们并希望尽可能多地使用它们。不过选择权在你手中。
答案4
你可以在不使用数组的情况下进行管理。设置独立财务顾问换行符将允许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 -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)