How to move workspace to monitor - archlinux

I regularly change physical setup (work from home and office) and need a flexible and quick way of changing workspace form monitor to monitor.
OS: Arch
Window Manager: i3

There are a number of ways to do this.
Use the command line:
$ i3-msg move workspace to output left
[{"success":true}]
$ i3-msg move workspace to output right
[{"success":true}]
$ i3-msg move workspace to output next
[{"success":true}]
Add bindsym binds in your i3 config file as per other answers (for regolith users here is a good example).
Use python:
#!/usr/bin/env python3
# pip install --user i3-py rich
import i3
import rich
DEBUG = False
outputs = i3.get_outputs()
workspaces = i3.get_workspaces()
focused_workspace = [w for w in workspaces if w["focused"] == True][0]
active_outputs = [o for o in outputs if o["active"] == True]
other_output = [o for o in active_outputs if o["name"] != focused_workspace["output"]][
0
]
if DEBUG:
print("outputs:")
rich.print(outputs)
print("workspaces:")
rich.print(workspaces)
print("focused_workspace:")
rich.print(focused_workspace)
print("active_outputs:")
rich.print(active_outputs)
print("other_workspace:")
rich.print(other_output)
# Send current workspace to other output
i3.command("move", "workspace to output " + other_output["name"])
See this gist for other versions.
When using i3-msg or i3.command possible syntax is move workspace to output left|right|down|up|current|primary|<output>.

I found a way to do that that fits my needs:
First I need to detect what are the monitors I currently have connected:
I'll use xrandr to list all active monitors.
Sample output:
$ xrandr --listactivemonitors
Monitors: 3
0: +*HDMI-1 1920/531x1080/299+0+0 HDMI-1
1: +eDP-1 1280/301x800/188+3840+280 eDP-1
2: +DP-2 1920/595x1080/336+1920+0 DP-2
and then pipe that into grep to extract the names of the outputs:
xrandr --listactivemonitors | grep '{{ OUTPUT_NUMBER }}:' | grep -Po '[^ ]*$'
First grep to isolate the desired output line
Second grep to get only the output name
And then I'll do some dirty copy/past into my i3 config file.
# move focused container to workspace
bindsym $mod+$alt+1 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '0:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+2 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '1:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+3 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '2:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+4 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '3:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+5 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '4:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+6 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '5:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+7 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '6:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+8 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '7:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+9 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '8:' | grep -Po '[^ ]*$')"
bindsym $mod+$alt+0 exec "i3-msg move workspace to output $(xrandr --listactivemonitors| grep '9:' | grep -Po '[^ ]*$')"
A simple reload of the configuration file will update the binding when I'm connected to a new set of monitors.
PS: this could surely be improved but it's a quick and efficient way of doing it that fits my needs.

Add this to your i3config
bindsym $mod+Ctrl+Shift+Left move workspace to output left
bindsym $mod+Ctrl+Shift+Right move workspace to output right
bindsym $mod+Ctrl+Shift+Up move workspace to output up
bindsym $mod+Ctrl+Shift+Down move workspace to output down
bindsym $mod+Ctrl+Shift+h move workspace to output left
bindsym $mod+Ctrl+Shift+l move workspace to output right
bindsym $mod+Ctrl+Shift+k move workspace to output up
bindsym $mod+Ctrl+Shift+j move workspace to output down

Related

Gitlab CI variables and script section give different results

I've searched a lot of examples but they did not work for me.
I'm trying to run linters for changed files when MR is opened.
My .gitlab-ci.yml
run_linters:
image: python:3
variables:
FILES: git diff --name-only $CI_MERGE_REQUEST_TARGET_BRANCH_NAME | grep *.py
before_script:
- python3 -m pip install black==21.5b1
- python3 -m pip install flake8==3.9.2
script:
- echo $FILES
- git diff --name-only $CI_MERGE_REQUEST_TARGET_BRANCH_NAME | grep *.py
- black --check $FILES
- flake8 $FILES
only:
- merge_requests
And I'm getting strange output.
echo $FILES says git diff --name-only main | grep incoming_file.py
incoming_file.py is the only file in that MR. Why is it around grep?
And git diff at script section says fatal: ambiguous argument 'main': unknown revision or path not in the working tree.
Why is filename present around grep?
Why are same git diff commands give different result?
Why is filename present around grep?
In bash when you refer to * this will expand and try to match the files/directories present in your current path, in your case since only the incoming_file.py is present, so it expands to this.
Why are same git diff commands give different result?
variables:
FILES: git diff --name-only $CI_MERGE_REQUEST_TARGET_BRANCH_NAME | grep *.py
When you define a variable in variables section, Gitlab doesnt execute the command, it simple populates the variable FILES with the string git diff --name-only $CI_MERGE_REQUEST_TARGET_BRANCH_NAME | grep *.py
Then in the script section, the runner expands *.py to incoming_file.py and $CI_MERGE_REQUEST_TARGET_BRANCH_NAME to main
that's why in echo you see git diff --name-only main | grep incoming_file.py
Here
- git diff --name-only $CI_MERGE_REQUEST_TARGET_BRANCH_NAME | grep *.py
You actually execute the command and you get the mentioned message

awk command not working with kubectl exec

From outside container:
$ kubectl exec -it ui-gateway-0 -- bash -c "ps -ef | grep entities_api_svc | head -1"
root 14 9 0 10:34 ? 00:00:02 /svc/bin/entities_api_svc
$ kubectl exec -it ui-gateway-0 -- bash -c "ps -ef | grep entities_api_svc | head -1 | awk '{print $2}'"
root 14 9 0 10:34 ? 00:00:02 /svc/bin/entities_api_svc
From inside container:
[root#ui-gateway-0 /]# ps -ef | grep entities_api_svc | head -1 | awk '{print $2}'
14
I find it easier to use single quotes on the sh/bash command argument so it is closer to what you would type in the shell:
kubectl exec -it ui-gateway-0 -- \
bash -c 'ps -ef | grep entities_api_svc | head -1 | awk "{print \$2}"'
This means the awk uses double quotes, which requires the shell variable marker $ to be escaped.
In the original command, the shell running kubectl was replacing $2 with a zero length string so awk would see only print, which prints the whole line
Multiple levels of nesting
Nested shell escaping gets very obscure very quickly and hard to debug:
$ printf '%q\n' 'echo "single nested $var" | awk "print $2"'
echo\ \"single\ nested\ \$var\"\ \|\ awk\ \"print\ \$2\"
$ printf '%q\n' "$(printf '%q\n' 'echo "double nested $var" | awk "print $2"')"
echo\\\ \\\"double\\\ nested\\\ \\\$var\\\"\\\ \\\|\\\ awk\\\ \\\"print\\\ \\\$2\\\"
If you add a file grep-entities.sh in container
#!/bin/bash
set -uex -o pipefail
ps -ef | grep entities_api_svc | head -1 | awk '{print $2}'
You then don't need to worry about escaping
pid=$(sshpass -p "password" ssh vm#10.10.0.1 kubectl exec ui-gateway-0 -- /grep-entities.sh)
Also pgrep does the scripts job for you
kubectl exec ui-gateway-0 -- pgrep entities_api_svc

Force write to Xcode 'Debugger Output' in console?

The Xcode console has a 'Debugger output' filter. I understand this is for use with lldb, and that you can get messages to print to this output by using breakpoints. My question is not how to do that.
My question is: what is the underlying mechanism Xcode itself uses to write lldb messages to Debugger Output (not Target Output)? Is there a variable similar to stdout or stderr that writes here? Is it possible, from Xcode target code (Swift/Obj-C/C), to write to this output?
Looks like Xcode uses a tty to communicate with lldb, and you can interface with the Debugger Output using that:
echo "Wheeeeeeee" > $(lsof -p $(ps -A | grep -m1 MacOS/Xcode | awk '{print $1}') | grep -m2 dev/ttys | tail -1 | awk '{print $9}')
Breaking the above down:
$ ps -A | grep -m1 MacOS/Xcode | awk '{print $1}'
21280
This gives the process ID of Xcode (21280). Using this, we can find the files it has open:
$ lsof -p 21280 | grep /dev/ttys
Xcode 21280 tres 47u CHR 16,3 0t0 3569 /dev/ttys003
Xcode 21280 tres 58u CHR 16,5 0t0 3575 /dev/ttys005
The one with the highest number (/dev/ttys005 in this case) is the one we want, so let's extract it. tail -1 will give us the last line of output, and awk '{print $9}' will give us the 9th item on the line, which is what we want!
$ lsof -p 21280 | grep /dev/ttys | tail -1 | awk '{print $9}'
/dev/ttys005
Now we can use this to write whatever we want:

extracting a number from a stream using sed/grep/awk

i am writting a script and i need to get a number out of the shell command output. The command & its return is
$ git branch -a -v --no-abbrev --contains $(git rev-parse HEAD)
* (HEAD detached at c5246b6) c5246b6907e46795741853852462914e7a5f60de Merge pull request 1166 from testPR into dev
remotes/origin-pull/1166/merge c5246b6907e46795741853852462914e7a5f60de Merge pull request 1166 from testPR into dev
i am trying to extract the 1166 out of the result by using sed over the piped result. Something like
$ git branch -a -v --no-abbrev --contains $(git rev-parse HEAD) | sed <pattern>
to get the 1166
My patterns so far doesn't seem to get the number i am expecting.
I seems that you're trying to extract the part of your remote branch name between last 2 slashes. And you may use grep with perl interpreted pattern to achieve that, here you are,
$ git branch ... | grep -oP '[^\/]+(?=\/[^\/]+$)'
1166
Brief explanation,
-o: Print only the matched (non-empty) parts
[^\/]+ : grep command would print this part, non-slash pattern
(?=\/[^\/]+$) : matches words ahead of the las slash of the line [^\/]+$
Not the answer to my exact question, but i am able to get what i want by modifying my bash command.
git branch -r -v --no-abbrev --contains $(git rev-parse HEAD) | awk '{print $1}'
This returns: origin-pull/1166/merge , which is what i want
notice the -r in the command, -a will return both local and remote git branch info. This way, i can cheat on the sed pattern again.

A script to change file names

I am new to awk and shell based programming. I have a bunch of files name file_0001.dat, file_0002.dat......file_1000.dat. I want to change the file names such as the number after file_ will be a multiple of 4 in comparison to previous file name. SO i want to change
file_0001.dat to file_0004.dat
file_0002.dat to file_0008.dat
and so on.
Can anyone suggest a simple script to do it. I have tried the following but without any success.
#!/bin/bash
a=$(echo $1 sed -e 's:file_::g' -e 's:.dat::g')
b=$(echo "${a}*4" | bc)
shuf file_${a}.dat > file_${b}.dat
This script will do that trick for you:
#!/bin/bash
for i in `ls -r *.dat`; do
a=`echo $i | sed 's/file_//g' | sed 's/\.dat//g'`
almost_b=`bc -l <<< "$a*4"`
b=`printf "%04d" $almost_b`
rename "s/$a/$b/g" $i
done
Files before:
file_0001.dat file_0002.dat
Files after first execution:
file_0004.dat file_0008.dat
Files after second execution:
file_0016.dat file_0032.dat
Here's a pure bash way of doing it (without bc, rename or sed).
#!/bin/bash
for i in $(ls -r *.dat); do
prefix="${i%%_*}_"
oldnum="${i//[^0-9]/}"
newnum="$(printf "%04d" $(( 10#$oldnum * 4 )))"
mv "$i" "${prefix}${newnum}.dat"
done
To test it you can do
mkdir tmp && cd $_
touch file_{0001..1000}.dat
(paste code into convert.sh)
chmod +x convert.sh
./convert.sh
Using bash/sed/find:
files=$(find -name 'file_*.dat' | sort -r)
for file in $files; do
n=$(sed 's/[^_]*_0*\([^.]*\).*/\1/' <<< "$file")
let n*=4
nfile=$(printf "file_%04d.dat" "$n")
mv "$file" "$nfile"
done
ls -r1 | awk -F '[_.]' '{printf "%s %s_%04d.%s\n", $0, $1, 4*$2, $3}' | xargs -n2 mv
ls -r1 list file in reverse order to avoid conflict
the second part will generate new filename. For example: file_0002.dat will become file_0002.dat file_0008.dat
xargs -n2 will pass two arguments every time to mv
This might work for you:
paste <(seq -f'mv file_%04g.dat' 1000) <(seq -f'file_%04g.dat' 4 4 4000) |
sort -r |
sh
This can help:
#!/bin/bash
for i in `cat /path/to/requestedfiles |grep -o '[0-9]*'`; do
count=`bc -l <<< "$i*4"`
echo $count
done