複数のアプリケーションを開いています。実行中マウスコントロール出力をパイプで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
も効果があることがわかりました。
どちらか一方を他方より優先する理由はあるでしょうか?
「sticky」と「gracefully」は からの用語です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
ただし、テストの合間にキャッシュされたバッファをフラッシュすることが重要です。
2 つのループの速度がほぼ同じである場合は、読みやすさが最も良いループを選択します。
ただし、この質問の範囲では、ほとんどの時間がユーザー入力の待機に費やされ、ほとんどのユーザーに対して最大 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
。
より短く、より読みやすいスクリプトを書くには、配列を使用する 2 つの方法があります。
#!/bin/bash
Windows=( $(wmctrl -l | awk ' !/-1/ { print $1 } ' ) )
for Window in "${Windows[@]}" ; do wmctrl -ia $Window -c $Window ; done
配列なしの2番目:
#!/bin/bash
Windows=$(wmctrl -l | awk ' !/-1/ { print $1 } ' )
for Window in $Windows ; do wmctrl -ia $Window -c $Window ; done
私は配列メソッドを好みます。配列メソッドについてもっと学び、できるだけ多く使用したいからです。ただし、選択はあなた次第です。
答え4
配列なしでも管理できます。設定IFSC の改行を使用すると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)