![从 wmctrl -l 中仅获取应用程序名称](https://linux22.com/image/104694/%E4%BB%8E%20wmctrl%20-l%20%E4%B8%AD%E4%BB%85%E8%8E%B7%E5%8F%96%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%90%8D%E7%A7%B0.png)
我试图从这段代码中获取应用程序名称:
wmctrl -l
但我不知道该怎么做!
如果您能解释一下我如何做到这一点,那就太好了。
编辑:
的输出wmctrl -l
是:
0x01000007 -1 parrot Top Expanded Edge Panel
0x01000017 -1 parrot Bottom Expanded Edge Panel
0x01200006 -1 parrot x-caja-desktop
0x03600006 0 parrot Terminal
0x03000130 0 parrot scripting - Getting a string after a word in BASH - Unix & Linux Stack Exchange - Google Chrome
所以我需要之后的一切parrot
答案1
有几种方法可以做到这一点。根据您喜欢的工具类型,您可以选择一种工具
AWK
最合适的方式。将单词 1,2,3 设置为空字符串并打印
$ wmctrl -l | awk '{$1=$2=$3="";print}'
或者,要消除前导空格,您可以执行以下操作:
$ wmctrl -l | awk '{for(i=4;i<=NF;i++) printf "%s ",$i;print ""}'
切
有点尴尬的方法,我们打印特定字段之后的所有内容,直到字段 9999。为什么是 9999 ?-f
flag 显然需要知道范围,因此对于每行具有任意数量单词的输入,我们显然无法知道范围,但我们可以使用足够大的东西,因此 9999。
$ wmctrl -l | cut -d " " -f 5-9999
珀尔
我们可以利用-a
自动分割模式,将从标准输入读取的每一行的字分割成数组。这可能会得到改进和缩短。
$ wmctrl -l | perl -lane 'my $numels=scalar @F;print @F[3..$numels]'
Python
有点长但有效。 Python 没有像 perl 那样的自动分割模式,但我们可以在读取每个字符串时手动执行此操作。
$ wmctrl -l | python -c "import sys; print '\n'.join([' '.join(line.split()[3:]) for line in sys.stdin])"
或者,我们可以使用一个简短的脚本来模拟cut
,而不是单行脚本。这对于多行文本/输入会更好,并且更具可读性
#!/usr/bin/env python
import sys
start=int(sys.argv[1])
for line in sys.stdin:
print " ".join(line.strip().split()[start:])
并这样称呼它:
$ wmctrl -l | ./print_words.py 3
SED
这种方式利用了正则表达式。我们从行首^
到单词边界匹配字符串parrot
以及\b
后面的空格,然后删除它们(有效设置为空字符串)
$ wmctrl -l | sed 's/^.*\bparrot\ //'
另外,为了避免贪婪匹配,我们可以使用以下方法:
$ wmctrl -l | sed 's/^[^ ]* *[^ ]* *[^ ]* //'
模式并不太复杂。我们从行首开始匹配,将任意数量的*
非空格(部分)的字符([^ ]
部分)匹配三遍,并以任意数量的空格分隔。因此 ^[^ ]*
匹配第一个单词,*
匹配任意数量的空格,第二个[^ ]*
匹配第二个单词,第二个*
匹配第二个空格,最后[^ ]*
匹配第三个单词加空格。
BASH + xargs
我们可以利用 bash 迭代命令行参数的能力,并将每一行 ( -L 1 ) 作为一组命令行参数传递给bash -c ' '
.剩下的很简单 - 我们去掉前 3 个参数,然后打印剩下的
wmctrl -l | xargs -L 1 bash -c 'for i in 1 2 3;do shift ; done ; printf "%s " "$@";printf "\n"' sh
或者,正如 Stephane Chazelas 在评论中所建议的:只要至少有 3 个位置参数被传递wmctrl -l
(在这种情况下应该始终为真),解决方案可以缩短为:
wmctrl -l | xargs -L 1 bash -c 'shift 3;printf "%s " "$@";printf "\n"' sh
答案2
答案3
sed -n 's/.* parrot //p'
将打印右侧的内容最右边的出现" parrot "
在包含 的行上" parrot "
。这是因为.*
上面是贪婪的,并且会尽可能匹配。
在你的情况下,这将是一个输出问题,如:
0x03a00003 0 parrot parrot (~) (1 of 2) - GVIM
如果你想打印右边的内容最左边发生时" parrot "
,一个常见的技巧是:
sed -n '/ parrot /{
s//\
/; s/.*/\n/p
}'
也就是说,我们" parrot "
用换行符(否则永远不会在模式空间中找到的字符)替换第一个(最左边)出现的 。然后删除换行符之前的所有内容(保证是唯一的)。
不过,在这里,您似乎想要从parrot
客户端获得窗口的标题,因此第三个字段所在的行parrot
,因此:
sed -n 's/^[^ ]\{1,\} \{1,\}[^ ]\{1,\} \{1,\}parrot //p'
或者与perl
:
perl -ne 'print if s/^\H+\h+\H+\h+parrot //'
请注意,我们假设窗口标题不包含换行符,这通常是这种情况,但不能保证。例如尝试之后:
xterm -n $'foo\nbar'
如果你想解释这一点,你可以这样做:
perl -0777 -ne '$prefix = qr{0x[\da-f]+\h+-?\d+\h+};
print for /^${prefix}parrot (.*?\n)(?=$prefix|$)/gms'
即使用所有条目开头的事实来0x<hex> <dec>
标识记录的开始和结束位置。这并不是完全万无一失的(就像有人这样做的情况一样xterm -n $'foo\n0x0 0 parrot something'
),但在不面对恶意用户时应该没问题。
答案4
您可以修剪固定宽度输出
wmctrl -l | cut -c15-