How to get the list of open windows from xserver - x11

Anyone got an idea how to get from an Xserver the list of all open windows?

From the CLI you can use
xwininfo -tree -root
If you need to do this within your own code then you need to use the XQueryTree function from the Xlib library.

If your window manager implements EWMH specification, you can also take a look at the _NET_CLIENT_LIST value of the root window. This is set by most modern window managers:
xprop -root|grep ^_NET_CLIENT_LIST
That value can easily be obtained programmatically, see your Xlib documentation!

Building off of Marten's answer, (assuming your window manager supports Extended Window Manager Hints) you can feed that list of window ids back into xprop to get the _NET_WM_NAME property:
$ xprop -root _NET_CLIENT_LIST |
pcregrep -o1 '# (.*)' |
sed 's/, /\n/g' |
xargs -I{} -n1 xprop -id {} _NET_WM_NAME
But at the command line, it would just be easier to use wmctrl:
$ wmctrl -l
Programmatically, with python-xlib, you can do the same with:
#!/usr/bin/env python
from Xlib.display import Display
from Xlib.X import AnyPropertyType
display = Display()
root = display.screen().root
_NET_CLIENT_LIST = display.get_atom('_NET_CLIENT_LIST')
_NET_WM_NAME = display.get_atom('_NET_WM_NAME')
client_list = root.get_full_property(
_NET_CLIENT_LIST,
property_type=AnyPropertyType,
).value
for window_id in client_list:
window = display.create_resource_object('window', window_id)
window_name = window.get_full_property(
_NET_WM_NAME,
property_type=AnyPropertyType,
).value
print(window_name)
Or, better yet, using the EWMH library:
#!/usr/bin/env python
from ewmh import EWMH
window_manager_manager = EWMH()
client_list = window_manager_manager.getClientList()
for window in client_list:
print(window_manager_manager.getWmName(window))

Related

Powershell script to list all open Explorer windows

This question shows a Powershell script to generate a list of open File Explorer windows and their path.
My goal is to capture the currently open set of explorer windows, and write out a CMD file with commands like: C:\WINDOWS\explorer.exe /e, "C:\open\this\folder"
So I would like to have the full path and folder name in normal path notation. This is what is showing in titlebar of the Explorer Windows: "C:\open\this\Favorite folder"
The proposed code is:
function Get-WindowTitle($handle) {
Get-Process |
Where-Object { $_.MainWindowHandle -eq $handle } |
Select-Object -Expand MainWindowTitle
}
$app = New-Object -COM 'Shell.Application'
$app.Windows() |
Select-Object LocationURL, #{n='Title';e={Get-WindowTitle $_.HWND}}
As shown above, LocationURL provides a full path in an escaped-URL style:
file:///C:/open/this/Favorite%20%folder"
The #{n='Title';e={Get-WindowTitle $_.HWND}} component produces a column "Title" which is truncated to 5 characters:
C:\...
The full output for one explorer window looks like:
LocationURL Title
----------- -----
file:///C:/open/this/Favorite%20%folder C:...
I found I could avoid the truncation by padding the string 'Title' with many spaces. That string's width seems to determine the maximum width of the output.
Still, I observe that only about 60% of the open explorer windows list a path. The rest are just a blank line.
I tried "$app.Windows() | Select-Object LocationName", but the output only contains the Explorer folder name only, not the full path and folder that is displayed in the Explorer title.
Another mystery is why the script runs so slowly. If I have 10 explorer windows open, the script runs for 30 seconds, taking about 3 seconds per path.
For this script:
function Get-WindowTitle($handle) {
Get-Process |
Where-Object { $_.MainWindowHandle -eq $handle } |
Select-Object -Expand MainWindowTitle
}
$app = New-Object -COM 'Shell.Application'
$app.Windows() |
Select-Object LocationName,#{n=' ------------Title---------------- ';e={Get-WindowTitle $_.HWND}}
This is the output (with some redacting with *** for privacy)
PS C:\E***> .\OpenExplorer.ps1
LocationName ------------Title----------------
------------ ----------------------------------------------------------------------------------
2019-07
Ame****
2019 Priv...
2019-10-3... C:\E\Event Presentations\2019-10-31 Priv**********bcast
E C:\E
5G Brief ... C:\E\Tech************ing\5G Brief (2018)
36 Series...
2019 DE* ... C:\E\16*****N\2019 DE*******************
Newsletters C:\E\Newsletters
Reports C:\E\Tech************ing\Reports
2019-10-2... C:\E\16**********s\2019-10-29 *********************
2019-11 C:\Data\Docs\Stand*********24\2019-11
UB****
Financial... C:\E\Financ************
Expenses C:\E\Internal\Expenses
E C:\E
E***
I assume what you're really interested is the local filesystem paths of the open Explorer windows, not necessarily the window titles (which aren't guaranteed to reflect the full paths).
Somewhat obscurely, the window objects returned by the .Windows() method contain the local path representation in their .Document.Folder.Self.Path property.
(New-Object -ComObject 'Shell.Application').Windows() | ForEach-Object {
$localPath = $_.Document.Folder.Self.Path
"C:\WINDOWS\explorer.exe /e, `"$localPath`""
}
The above produces output such as:
C:\WINDOWS\explorer.exe /e, "C:\Users\jdoe"
C:\WINDOWS\explorer.exe /e, "C:\Program Files"
You can output this to a batch file file as needed, e.g. by appending | Set-Content file.cmd to the above command.
Note: The windows are listed in the order in which they were created, so you cannot infer which among them was most recently activated. See this answer for a solution that finds the topmost File Explorer window and determines the path shown in it.
I found I could avoid the truncation
The truncation is just a display artifact - the data is still there.
You can make the data visible in one of two ways:
pipe to Format-Table -AutoSize to make sure that column values aren't truncated, space permitting
pipe to Format-List, which will show each property on its own line (line-wrapping overly long values).

what ps -e -o user:20, pid means?

I have a already written script which has this line PID = ps -e -o user:20,pid,cmd
Could anybody explain me the meaning of this line? I am bit confused with user:20 part
Thanks!
ps is a command name used to show processes running in the system currently.
-e is a "short" option which means that all processes should be listed.
-o user:20,pid,cmd is an option which sets expected format of lines to be printed on screen, i.e. we want the first column to contain usernames (who own the processes) padded to 20 characters, the second column to show process IDs and the third column to contain command names which have been used to start the processes. Just that.
Also, you can simply try to run this yourself in your terminal: ps -e -o user:20,pid,cmd and see what happens.
From ps's man page:
-o format
User-defined format. format is a single argument in the form of a blank-separated or comma-separated list, which offers a way to specify
individual output columns. The recognized keywords are described in the STANDARD FORMAT SPECIFIERS section below. Headers may be renamed (ps
-o pid,ruser=RealUser -o comm=Command) as desired. If all column headers are empty (ps -o pid= -o comm=) then the header line will not be
output. Column width will increase as needed for wide headers; this may be used to widen up columns such as WCHAN (ps -o pid,wchan=WIDE-
WCHAN-COLUMN -o comm). Explicit width control (ps opid,wchan:42,cmd) is offered too. The behavior of ps -o pid=X,comm=Y varies with
personality; output may be one column named "X,comm=Y" or two columns named "X" and "Y". Use multiple -o options when in doubt. Use the
PS_FORMAT environment variable to specify a default as desired; DefSysV and DefBSD are macros that may be used to choose the default UNIX or
BSD columns.
Explicit width control (ps opid,wchan:42,cmd) is offered too.
So you'll get a user column with 20-char's width.
ps - This command report a snapshot of the current processes.
-e , This options helps to select all processes.Identical to -A.
-o , This options helps to specify user-defined format.
user:20 ,
This will help to format the output of ps command.The user:20 will add some extra 20 space character betweens the columns. Below the example will help you to find the difference.
jdeveloper#jdeveloper ~ $ ps -e -o user:20,pid
USER PID
root 2926
jdeveloper 2948
root 3255
root 3570
root 3802
jdeveloper 3825
jdeveloper 3860
Now , lets try with 10 character space padding in response.
jdeveloper#jdeveloper ~ $ ps -e -o user:10,pid
USER PID
root 2926
jdeveloper 2948
root 3255
root 3570
root 3802
jdeveloper 3825
jdeveloper 3863
Find more about ps command using man command.Try
jdeveloper#jdeveloper ~ $ man ps
Hope it will help you.

xdotool and keyboard layout

Problem
I am trying to do:
xdotool type 'date;'
but instead of the expected
date;
I get:
dateq
I have a greek keyboard, but when I issue the command the language is set to US. A note: when greek language is used, the key 'q' of the keyboard is used for the semicolon ';' (this is the default behavior/mapping)
Question
What can I do to get a semicolon with xdotool's type?
Some info
I am on Xfce 4.8 on XUbuntu
$ xfce4-terminal -V
xfce4-terminal 0.4.8 (Xfce 4.8)
$ setxkbmap -print -verbose 10
Setting verbose level to 10
locale is C
Applied rules from evdev:
rules: evdev
model: pc105
layout: us,gr
variant: ,
options: grp:caps_toggle
Trying to build keymap using the following components:
keycodes: evdev+aliases(qwerty)
types: complete
compat: complete
symbols: pc+us+gr:2+inet(evdev)+capslock(grouplock)
geometry: pc(pc105)
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_symbols { include "pc+us+gr:2+inet(evdev)+capslock(grouplock)" };
xkb_geometry { include "pc(pc105)" };
};
$ sudo lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 12.04.2 LTS
Release: 12.04
Codename: precise
try
setxkbmap <yourlocale>
before calling xdotool
This is a known bug. One thing you can try is upgrading to the newest version of xdotool. If that doesn't work, then check out this page, especially answer #29:
http://code.google.com/p/semicomplete/issues/detail?id=13
The issue was resolved by this pull request on 2014-04-07 (which is more than 3 years ago now). If anybody is still having this issue today, I think your best bet is upgrading xdotool.
These work for me:
echo "date;" | xvkbd -xsendevent -file -
xvkbd -xsendevent -text 'date;'
(remove the -xsendevent option and you get the same problem as with xdotool)
extending fazae's answer:
I have the latest version of xdotool, it seems. But the bug is still there:
$ xdotool --version
xdotool version 2.20110530.1
$ xdotool type ';'
$
'$' is typed instead of ';'.
$ xdotool type ':'
^
'^' is typed instead of ':'
FIX (example for the us and ru locales, alt+shift for toggling layouts): set locale to us, enable layout toggling with alt+shift:
$ setxkbmap us && xdotool type ':' && setxkbmap -option grp:alt_shift_toggle us,ru
:

pexpect responses includes echos of requests with <cr>

I have used pexpect and sendline before, but this time I am running a longer command with pipes and wild card, see below:
commandToRun='/bin/bash -c "/var/scripts/testscripts//extract -o | tail -3"'
returnedString = sendLine(commandToRun)
my class which has the sendLine function looks pretty much like this:
self.connection = pexpect.spawn('%s %s' % (protocol, host))
self.connection.setecho(False)
self.connection.setwinsize(300, 300)
But when I was running the code, I saw that the returnedString not only includes the response it also includes the request as well.
So if I print returnedString, it look like this:
bin/bash -c "/var/scripts/testscripts//extract -o | tail -3"<cr>
100<cr>
102<cr>
103<cr>
Why does the response includes the request in the same buffer?
I have already set setecho(False) and it does not help!
EDIT: (correct fix) I have to manually remove all from the response and remove the request as well. so setecho(False) still does nothing!
I found a solution to this myself. (turn off echo in response)
commandToRun = 'bash -c "less /readfile | tail -4"'
yourConnection.sendLine("stty -echo")
commandResult = yourConnection.sendLine(commandToRun)
self.sendLine("stty echo")
So basically, run you command in a shell using 'bash -c' and then turn of echo in the bash.

Unix tail equivalent command in Windows Powershell

I have to look at the last few lines of a large file (typical size is 500MB-2GB). I am looking for a equivalent of Unix command tail for Windows Powershell. A few alternatives available on are,
http://tailforwin32.sourceforge.net/
and
Get-Content [filename] | Select-Object -Last 10
For me, it is not allowed to use the first alternative, and the second alternative is slow. Does anyone know of an efficient implementation of tail for PowerShell.
Use the -wait parameter with Get-Content, which displays lines as they are added to the file. This feature was present in PowerShell v1, but for some reason not documented well in v2.
Here is an example
Get-Content -Path "C:\scripts\test.txt" -Wait
Once you run this, update and save the file and you will see the changes on the console.
For completeness I'll mention that Powershell 3.0 now has a -Tail flag on Get-Content
Get-Content ./log.log -Tail 10
gets the last 10 lines of the file
Get-Content ./log.log -Wait -Tail 10
gets the last 10 lines of the file and waits for more
Also, for those *nix users, note that most systems alias cat to Get-Content, so this usually works
cat ./log.log -Tail 10
As of PowerShell version 3.0, the Get-Content cmdlet has a -Tail parameter that should help. See the technet library online help for Get-Content.
I used some of the answers given here but just a heads up that
Get-Content -Path Yourfile.log -Tail 30 -Wait
will chew up memory after awhile. A colleague left such a "tail" up over the last day and it went up to 800 MB. I don't know if Unix tail behaves the same way (but I doubt it). So it's fine to use for short term applications, but be careful with it.
PowerShell Community Extensions (PSCX) provides the Get-FileTail cmdlet. It looks like a suitable solution for the task. Note: I did not try it with extremely large files but the description says it efficiently tails the contents and it is designed for large log files.
NAME
Get-FileTail
SYNOPSIS
PSCX Cmdlet: Tails the contents of a file - optionally waiting on new content.
SYNTAX
Get-FileTail [-Path] <String[]> [-Count <Int32>] [-Encoding <EncodingParameter>] [-LineTerminator <String>] [-Wait] [<CommonParameters>]
Get-FileTail [-LiteralPath] <String[]> [-Count <Int32>] [-Encoding <EncodingParameter>] [-LineTerminator <String>] [-Wait] [<CommonParameters>]
DESCRIPTION
This implentation efficiently tails the cotents of a file by reading lines from the end rather then processing the entire file. This behavior is crucial for ef
ficiently tailing large log files and large log files over a network. You can also specify the Wait parameter to have the cmdlet wait and display new content
as it is written to the file. Use Ctrl+C to break out of the wait loop. Note that if an encoding is not specified, the cmdlet will attempt to auto-detect the
encoding by reading the first character from the file. If no character haven't been written to the file yet, the cmdlet will default to using Unicode encoding
. You can override this behavior by explicitly specifying the encoding via the Encoding parameter.
Probably too late for an answere but, try this one
Get-Content <filename> -tail <number of items wanted> -wait
Just some additions to previous answers. There are aliases defined for Get-Content, for example if you are used to UNIX you might like cat, and there are also type and gc. So instead of
Get-Content -Path <Path> -Wait -Tail 10
you can write
# Print whole file and wait for appended lines and print them
cat <Path> -Wait
# Print last 10 lines and wait for appended lines and print them
cat <Path> -Tail 10 -Wait
I have a useful tip on this subject concerning multiple files.
Following a single log file (like 'tail -f' in Linux) with PowerShell 5.2 (Win7 and Win10) is easy (just use "Get-Content MyFile -Tail 1 -Wait"). However, watching MULTIPLE log files at once seems complicated. With PowerShell 7.x+ however, I've found an easy way by using "Foreach-Object -Parrallel". This performs multiple 'Get-Content' commands concurrently. For example:
Get-ChildItem C:\logs\*.log | Foreach-Object -Parallel { Get-Content $_ -Tail 1 -Wait }
Using Powershell V2 and below, get-content reads the entire file, so it was of no use to me. The following code works for what I needed, though there are likely some issues with character encodings. This is effectively tail -f, but it could be easily modified to get the last x bytes, or last x lines if you want to search backwards for line breaks.
$filename = "\wherever\your\file\is.txt"
$reader = new-object System.IO.StreamReader(New-Object IO.FileStream($filename, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [IO.FileShare]::ReadWrite))
#start at the end of the file
$lastMaxOffset = $reader.BaseStream.Length
while ($true)
{
Start-Sleep -m 100
#if the file size has not changed, idle
if ($reader.BaseStream.Length -eq $lastMaxOffset) {
continue;
}
#seek to the last max offset
$reader.BaseStream.Seek($lastMaxOffset, [System.IO.SeekOrigin]::Begin) | out-null
#read out of the file until the EOF
$line = ""
while (($line = $reader.ReadLine()) -ne $null) {
write-output $line
}
#update the last max offset
$lastMaxOffset = $reader.BaseStream.Position
}
I found most of the code to do this here.
I took #hajamie's solution and wrapped it up into a slightly more convenient script wrapper.
I added an option to start from an offset before the end of the file, so you can use the tail-like functionality of reading a certain amount from the end of the file. Note the offset is in bytes, not lines.
There's also an option to continue waiting for more content.
Examples (assuming you save this as TailFile.ps1):
.\TailFile.ps1 -File .\path\to\myfile.log -InitialOffset 1000000
.\TailFile.ps1 -File .\path\to\myfile.log -InitialOffset 1000000 -Follow:$true
.\TailFile.ps1 -File .\path\to\myfile.log -Follow:$true
And here is the script itself...
param (
[Parameter(Mandatory=$true,HelpMessage="Enter the path to a file to tail")][string]$File = "",
[Parameter(Mandatory=$true,HelpMessage="Enter the number of bytes from the end of the file")][int]$InitialOffset = 10248,
[Parameter(Mandatory=$false,HelpMessage="Continuing monitoring the file for new additions?")][boolean]$Follow = $false
)
$ci = get-childitem $File
$fullName = $ci.FullName
$reader = new-object System.IO.StreamReader(New-Object IO.FileStream($fullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [IO.FileShare]::ReadWrite))
#start at the end of the file
$lastMaxOffset = $reader.BaseStream.Length - $InitialOffset
while ($true)
{
#if the file size has not changed, idle
if ($reader.BaseStream.Length -ge $lastMaxOffset) {
#seek to the last max offset
$reader.BaseStream.Seek($lastMaxOffset, [System.IO.SeekOrigin]::Begin) | out-null
#read out of the file until the EOF
$line = ""
while (($line = $reader.ReadLine()) -ne $null) {
write-output $line
}
#update the last max offset
$lastMaxOffset = $reader.BaseStream.Position
}
if($Follow){
Start-Sleep -m 100
} else {
break;
}
}
try Windows Server 2003 Resource Kit Tools
it contains a tail.exe which can be run on Windows system.
https://www.microsoft.com/en-us/download/details.aspx?id=17657
There have been many valid answers, however, none of them has the same syntax as tail in linux. The following function can be stored in your $Home\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 for persistency (see powershell profiles documentation for more details).
This allows you to call...
tail server.log
tail -n 5 server.log
tail -f server.log
tail -Follow -Lines 5 -Path server.log
which comes quite close to the linux syntax.
function tail {
<#
.SYNOPSIS
Get the last n lines of a text file.
.PARAMETER Follow
output appended data as the file grows
.PARAMETER Lines
output the last N lines (default: 10)
.PARAMETER Path
path to the text file
.INPUTS
System.Int
IO.FileInfo
.OUTPUTS
System.String
.EXAMPLE
PS> tail c:\server.log
.EXAMPLE
PS> tail -f -n 20 c:\server.log
#>
[CmdletBinding()]
[OutputType('System.String')]
Param(
[Alias("f")]
[parameter(Mandatory=$false)]
[switch]$Follow,
[Alias("n")]
[parameter(Mandatory=$false)]
[Int]$Lines = 10,
[parameter(Mandatory=$true, Position=5)]
[ValidateNotNullOrEmpty()]
[IO.FileInfo]$Path
)
if ($Follow)
{
Get-Content -Path $Path -Tail $Lines -Wait
}
else
{
Get-Content -Path $Path -Tail $Lines
}
}
Very basic, but does what you need without any addon modules or PS version requirements:
while ($true) {Clear-Host; gc E:\test.txt | select -last 3; sleep 2 }
It is possible to download all of the UNIX commands compiled for Windows from this GitHub repository: https://github.com/George-Ogden/UNIX
For those admins who live by the axiom that less typing is best, here is the shortest version I can find:
gc filename -wai -ta 10

Resources