But why use PowerShell.. on Linux?
One reason is the beauty of the language and
the powerful capability of the object-piping*.
*) https://www.starwindsoftware.com
/blog/using-powershell-on-linux
Install Powershell on Linux Debian 11
(https://docs.microsoft.com/en-us/powershell/scripting/install/install-debian?view=powershell-7.2)
Install up-pwsh
:
#!/bin/bash
if [ "$UID" -ne "0" ]
then
echo "You are not root, exiting.."
exit 1
fi
apt update && apt -y upgrade && apt install -y wget
URL="https://packages.microsoft.com/config/debian/"
URL+="11/packages-microsoft-prod.deb"
wget $URL
dpkg -i packages-microsoft-prod.deb
apt update
apt install -y powershell
rm -f packages-microsoft-prod.deb
Remove down-pwsh
:
#!/bin/bash
if [ "$UID" -ne "0" ]
then
echo "You are not root, exiting.."
exit 1
fi
# Remove Microsoft repo
rm -f /etc/apt/sources.list.d/microsoft-prod.list
apt update
# Remove PowerShell
apt autoremove --purge -y powershell 2> /dev/null
rm -rf /usr/local/share/ca-certificates/
..Well now, what shall I talk about? There are, of course, any number of things I could talk about. I could take the egotistical approach and talk about myself, elucidating all those quirks of genetics and upbringing that brought me to the place of creating Perl, as well as making a fool of myself in general. That might be entertaining, at least to me.
.."Do one thing and do it well" was the rallying cry, and with one stroke, shell programmers were condemned to a life of muttering and counting beads on strings (which in these latter days have come to be known as pipelines).. This was when I made my small contribution to saving the world. I was rolling some of those very beads around in my fingers one day and pondering the hopelessness (and haplessness) of my existence, when it occurred to me that it might be interesting to melt down some of those mystical beads and see what would happen to their Magic if I made a single, slightly larger bead out of them. So I fired up the old Bunsen burner, picked out some of my favorite beads, and let them melt together however they would. And lo! the new Magic was more powerful than the sum of its parts and parcels.
..The Amulet isn't exactly beautiful though -- in fact, up close it still looks like a bunch of beads melted together. Well, all right, I admit it. It's downright ugly. But never mind that. It's the Magic that counts.
Larry Wall
September, 1993
https://www.cs.ait.ac.th/~on/O/oreilly/perl/learn32/prf1_01.htm
.. будучи на кухне, пришла одна мысль на тему предыдущего выступления:
Я слил остатки супов в одну кастрюлю и размешал -- получилось вполне съедобно. Про историю пиццы и фруктового желе даже не стану вникать в детали -- "..из всего, что осталось". Это Perl!.. Но я пошел дальше и вывалил все три полученных блюда в одно корыто. Это (вы подумали помои?) Powershell!, решил я.
1..6 | % { 1,2,8,10,16 | % { $_ }}
1 | % { $_ ? "too much" : "not enough" }
too much
0 | % { $_ ? "too much" : "not enough" }
not enough
Для начала уясним, что echo
является синонимом Write-Output
.
Write-Host
является продвинутым аналогом Write-Output
.
write-host hi -NoNewline "welt"
Easiest way to Shuffle an Array with PowerShell
1..30 | Sort-Object {Get-Random}
https://ilovepowershell.com/2015/01/24/easiest-way-shuffle-array-powershell/
Get-Alias | out-string -stream | Select-string "wri"
Get-Command | Where {$_.NAME -match "Wri"}
https://devblogs.microsoft.com/powershell/how-does-select-string-work-with-pipelines-of-objects/
IO
PS> $x=Read-Host
something weird
PS> Write-Host $x
something weird
binary to decimal
"10000111110" | % { [convert]::ToInt64($_,2) }
output
1086
split string by regular expression
PS> "1101 11 10010" -split "\s+"
output
1101
11
10010
read tape of
PS> "1000100 1000110 1001011" -split "\s+" | `
% { [char][convert]::ToInt32($_,2) }
output
D
F
K
pass through pipe
%
-- ForEach
commandlet
$_
-- default variable
{}
-- block, everything created inside the block, dies on exit block
PS> gc .\ansi.txt
output
In the town where I was born
Lived a man who sailed to sea
And he told us of his life
In the land of submarines
output
gc ./ansi.txt | % { $_ }
output
In the town where I was born
Lived a man who sailed to sea
And he told us of his life
In the land of submarines
display verse verically (in one column)
PS> cat .\ansi.txt | % { $_.toCharArray() | % { $_ } }
out
I
n
..
s
converts text in ansi.txt file to string of binaries
$s = ""
gc .\ansi.txt |
% { $_.toCharArray() |
% { $s+=[Convert]::ToString([int]$_,2); $s+=" " } }
$s
out
1001001 1101110 100000 1110100 1101000 1100101 100000
1110100 1101111 1110111 1101110 100000 1110111 1101000
1100101 1110010 1100101 100000 1001001 100000 1110111
1100001 1110011 100000 1100010 1101111 1110010 1101110
1001100 1101001 1110110 1100101 1100100 100000 1100001
100000 1101101 1100001 1101110 100000 1110111 1101000
1101111 100000 1110011 1100001 1101001 1101100 1100101
1100100 100000 1110100 1101111 100000 1110011 1100101
1100001 1000001 1101110 1100100 100000 1101000 1100101
100000 1110100 1101111 1101100 1100100 100000 1110101
1110011 100000 1101111 1100110 100000 1101000 1101001
1110011 100000 1101100 1101001 1100110 1100101 1001001
1101110 100000 1110100 1101000 1100101 100000 1101100
1100001 1101110 1100100 100000 1101111 1100110 100000
1110011 1110101 1100010 1101101 1100001 1110010 1101001
1101110 1100101 1110011
shorter if
$CarColor = 'Blue'
$x = @{
$true = 'The car color is blue';
$false = 'The car color is not blue'
}
$x[$CarColor -eq 'Blue']
output
The car color is blue
string length
PS> "abc" | % { $_.length }
output
3
Text to binaries and back s.ps1
$a = $s = ""
Get-Content .\ansi.txt |
% { $_.toCharArray() |
% { $s+=[Convert]::ToString([int]$_,2); $s+=" " }
$s+="1010 "
}
$s
" oooooooo "
$s -split "\s+" |
% {
if ($_.length -ne 0) {
$a += [char][Convert]::ToInt32($_,2)
}
}
$a
output
PS> ./s.ps1
1001001 1101110 100000 1110100 1101000 1100101 100000
1110100 1101111 1110111 1101110 100000 1110111 1101000
1100101 1110010 1100101 100000 1001001 100000 1110111
1100001 1110011 100000 1100010 1101111 1110010 1101110
1010 1001100 1101001 1110110 1100101 1100100 100000
1100001 100000 1101101 1100001 1101110 100000 1110111
1101000 1101111 100000 1110011 1100001 1101001 1101100
1100101 1100100 100000 1110100 1101111 100000 1110011
1100101 1100001 1010 1000001 1101110 1100100 100000
1101000 1100101 100000 1110100 1101111 1101100 1100100
100000 1110101 1110011 100000 1101111 1100110 100000
1101000 1101001 1110011 100000 1101100 1101001 1100110
1100101 1010 1001001 1101110 100000 1110100 1101000
1100101 100000 1101100 1100001 1101110 1100100 100000
1101111 1100110 100000 1110011 1110101 1100010 1101101
1100001 1110010 1101001 1101110 1100101 1110011 1010
oooooooo
In the town where I was born
Lived a man who sailed to sea
And he told us of his life
In the land of submarines
Validators
Boolean
$false -match '^(True|False)$'
output:
True
Integer
'+2718281828' -match '^[+-]?[1-9][0-9]*|0$'
Real. If you also want to match numbers with exponents, you can use:
'-1.45e-3' -match
'^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$'
output:
True
Learn AWK/ARDUINO/PROCESSING
template: BEGIN LOOP END
include the functions into your session.
Learn $input
variable.
PS> gc myfunc.ps1
Function Echo-Pipe {
Begin { "revisiting AWK BEGIN" }
# Executes once for each pipeline object
Process { echo $_ }
End { "revisiting AWK END" }
}
Function Echo-Pipe2 { foreach ($i in $input) { $i } }
PS> . .\myfunc.ps1
PS> cat data.txt | Echo-Pipe
output
revisiting AWK BEGIN
In the town where I was born
Lived a man who sailed to sea
And he told us of his life
In the land of submarines
revisiting AWK END
PS> gc data.txt | Echo-Pipe2
output:
In the town where I was born
Lived a man who sailed to sea
And he told us of his life
In the land of submarines
Important ?
Commandlet -- Where-Object
4 ways to operate with Windows Services.
services.msc
Get-Service | ? {$_.StartType -eq "Automatic"}
PS#> Start-Service sshd
PS#> Set-Service -Name sshd -StartupType 'Automatic'
CMD#> net start|stop|pause <servicename>
CMD#> sc start|stop|create|delete|query <servicename>
*) ? -- Where-Object
Search
PS> gc .\ansi.txt
In the town where I was born
Lived a man who sailed to sea
And he told us of his life
In the land of submarines
PS> gc .\ansi.txt | Select-String -Pattern '^[^AEIOU]'
Lived a man who sailed to sea
^
Search and Replace. BackReference and BackTick.
PS> Write-Output "ABA" | % { $_ -Replace "(B)","`$1`$1" }
ABBA
Coloring text
Basic idea -- Store Escape character in variable first:
PS\> $esc = "$([char]27)"
$esc[90m
$esc[90m
$esc[91m
$esc[92m
$esc[93m
$esc[94m
$esc[95m
$esc[96m
$esc[97m
$esc[0m
Synthetic command (visible colors):
"$esc[90mDARK$esc[91mRED$esc[92mGREEN$esc[94mBLUE" + `
"$esc[93mYELLOW$esc[96mCYAN$esc[95mMAGENTA$esc[0m"
Reset to defaults (Reset all):
$esc[0m
output format with Out-File
PS> Write-Output "kukarekuuu..!" |
Out-File demo -Encoding ascii
PS> Get-Content demo
kukarekuuu..!
(also: ascii
, bigendianunicode
, default
, oem
, string
, unicode
, unknown
, utf32
, utf7
, utf8
)
Read file line by line in PowerShell
$regex = "w"
PS> gc .\ansi.txt | ? {$_ -match $regex} | % { $_ }
In the town where I was born
Lived a man who sailed to sea
Read argument
PS> args.ps1
gc $args[0]
PS> .\args.ps1 .\file.txt
In the town where I was born
Lived a man who sailed to sea
And he told us of his life
In the land of submarines
Read variable from file
$text = gc $filePath -Raw
Write variable to a file
$hello | Out-File c:\debug.txt
Arguments
foo.ps1
param(
[Parameter(
Position=0,
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)
]
[Alias('Arguments')]
[String[]]$Args
)
foreach($path in $Args) {
Write-Host "file path is: $path"
}
Best Practices:
1
. !: Use full cmdlet name in scripts (not alias)
Get-Command -CommandType Alias ~300
% -> ForEach-Object
? -> Where-Object
echo -> Write-Output
gc -> Get-Content
2
. B: Use named parameters in scripts (not positional
and partial parameters)
3
. T: Avoid Write-Host
8
. !: Use WhatIf and Confirm parameters
WhatIf : Only displays the objects that would be affected and what changes would be made to those objects (without the worry of modifying those objects)
Confirm: Stops processing before any changes are made to an object.
10
. !: Avoid empty Catch block
11
. !: Use Set-StrictMode
in your dev scripts
Set-StrictMode -Version Latest
21
. !: Use #Requires
statement
#Requires -Version 3.0
#Requires -Modules ActiveDirectory, DnsClient
#Requires -RunAsAdministrator
where
B
-- inherited from common practices
T
-- like Taylor rules for Linux
!
-- Important
https://stackoverflow.com/questions/29119383/powershell-use-regular-expression-to-split-a-string
https://adamtheautomator.com/a-simpler-ifthen-conditional-logic-in-powershell/
https://www.ntu.edu.sg/home/ehchua/programming/howto/Regexe.html
https://www.regular-expressions.info/floatingpoint.html
https://stackoverflow.com/questions/53867147/grep-and-sed-equivalent-in-powershell
https://devblogs.microsoft.com/scripting/powertip-use-powershell-to-check-string-for-a-match/
https://stackoverflow.com/questions/33511772/read-file-line-by-line-in-powershell
https://stackoverflow.com/questions/5592531/how-to-pass-an-argument-to-a-powershell-script
https://stackoverflow.com/questions/7976646/powershell-store-entire-text-file-contents-in-variable
https://stackoverflow.com/questions/19122755/output-echo-a-variable-to-a-text-file
! #1: Use full cmdlet name in scripts (not alias)
Get-Command -CommandType Alias ~300
% -> ForEach-Object
? -> Where-Object
B #2: Use named parameter in scripts
(not positional and partial parameter)
T #3: Avoid Write-Host
#4: Use CIM cmdlet (not WMI cmdlet)
B #5: Avoid excessive comments (over-commenting)
#6: Use singular noun for cmdlet (not plural noun, boat -- boats)
#7: Use approved verb
(not unapproved verb, Get-Verb vs all other verbs)
! #8: Use WhatIf and Confirm parameters
WhatIf : Only displays the objects that would be affected
and what changes would be made to those objects
(without the worry of modifying those objects)
Confirm: Stops processing before any changes are made
to an object.
B #9: It is recommended to use region statement to split your code
into logical parts in your scripts.
! #10: Avoid empty Catch block
! #11: Use Set-StrictMode in your dev scripts
Set-StrictMode -Version Latest
#12: Avoid Out-Null cmdlet
#13: Avoid doublequotes in strings if not necessary
(Use proper quotes: 'strict' or "weak")
#14: Specify the extension for applications
#15: Execute scripts with -NoProfile parameter
#16: Update the help
#17: Use the same parameter name than the native one
#18: Don’t use Notepad as a script editor (use PS ISE or VS Code)
#19: Check parameters with PSBoundParameters
#20: Use full key name for calculated properties
! #21: Use #Requires statement
#Requires -Version 3.0
#Requires -Modules ActiveDirectory, DnsClient
#Requires -RunAsAdministrator
#22: Use Obsolete attribute for backwards compatibility
B #23: Avoid the horizontal scrolling (too long one-liners commands)*
That's it.
PS D:\TMP\Ps> Get-Verb | Measure-Object
Count : 98
Average :
Sum :
Maximum :
Minimum :
Property :
PS D:\TMP\Ps> Get-Verb
Verb Group
---- -----
Add Common
Clear Common
Close Common
Copy Common
Enter Common
Exit Common
Find Common
Format Common
Get Common
Hide Common
Join Common
Lock Common
Move Common
New Common
Open Common
Optimize Common
Pop Common
Push Common
Redo Common
Remove Common
Rename Common
Reset Common
Resize Common
Search Common
Select Common
Set Common
Show Common
Skip Common
Split Common
Step Common
Switch Common
Undo Common
Unlock Common
Watch Common
Backup Data
Checkpoint Data
Compare Data
Compress Data
Convert Data
ConvertFrom Data
ConvertTo Data
Dismount Data
Edit Data
Expand Data
Export Data
Group Data
Import Data
Initialize Data
Limit Data
Merge Data
Mount Data
Out Data
Publish Data
Restore Data
Save Data
Sync Data
Unpublish Data
Update Data
Approve Lifecycle
Assert Lifecycle
Complete Lifecycle
Confirm Lifecycle
Deny Lifecycle
Disable Lifecycle
Enable Lifecycle
Install Lifecycle
Invoke Lifecycle
Register Lifecycle
Request Lifecycle
Restart Lifecycle
Resume Lifecycle
Start Lifecycle
Stop Lifecycle
Submit Lifecycle
Suspend Lifecycle
Uninstall Lifecycle
Unregister Lifecycle
Wait Lifecycle
Debug Diagnostic
Measure Diagnostic
Ping Diagnostic
Repair Diagnostic
Resolve Diagnostic
Test Diagnostic
Trace Diagnostic
Connect Communications
Disconnect Communications
Read Communications
Receive Communications
Send Communications
Write Communications
Block Security
Grant Security
Protect Security
Revoke Security
Unblock Security
Unprotect Security
Use Other
==========
Solve in Powershell:
PRINT BINARY NUMBERS WITH LEADING ZEROES, LIKE SO:
0 00
1 01
2 10
3 11
..
awk solution
# awk -f 1.awk
BEGIN {
N=3; # number of bits
n=1; a[0]="";
for(i=0;i<3;i++) {
for(j=0;j<n;j++) {
a[n+j]="1"a[j];
a[j]="0"a[j];
}
n+=j;
}
for(i=0;i<n;i++)
print i," ", a[i];
}
PRINT BINARY NUMBERS WITH LEADING ZEROES, LIKE SO:
00 01 10 11
awk solution
# awk -f 2.awk
BEGIN {
ORS=" "; # the output record separator
N=3; # number of bits
n=1; a[0]="";
for(i=0;i<3;i++) {
for(j=0;j<n;j++) {
a[n+j]="1"a[j];
a[j]="0"a[j];
}
n+=j;
}
for(i=0;i<n;i++)
print a[i];
ORS="\n"; print;
}
PRINT TRUTH TABLE FOR NOT, OR, XOR, AND
# gawk -f 3.awk
BEGIN {
n=1; a[0]="";
for(i=0;i<2;i++) {
for(j=0;j<n;j++) {
a[n+j]="1"a[j];
a[j]="0"a[j];
}
n+=j;
}
print "n","ab","!a","!b","OR","XOR","AND"
for(i=0;i<n;i++)
print i, a[i], "",
xor(rshift(and(i,2),1),1), "",
xor(and(i,1),1), "",
or(and(i,1),rshift(and(i,2),1)), "",
xor(and(i,1),rshift(and(i,2),1)), "",
and(and(i,1),rshift(and(i,2),1));
}
$ gawk -f 2.awk
n ab !a !b OR XOR AND
0 00 1 1 0 0 0
1 01 1 0 1 1 0
2 10 0 1 1 1 0
3 11 0 0 1 0 1
PRINT CYRILLIC ALPHABET
# awk -f 4.awk
function chr(c) {
return sprintf("%c",c+0)
}
BEGIN {
ORS=""
for (x=0x410;x<=0x44f;x++) {
if(x==0x430) print "\n";
print chr(x);
}
ORS="\n"; print;
}
АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ
абвгдежзийклмнопрстуфхцчшщъыьэюя
ALFRED VAIL'S CODE (MORSE CODE)
# awk -f 5.awk
BEGIN {
si="ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
s=".-:-...:-.-.:-..:.:..-.:--.:....:..:.---:-.-:";
s=s".-..:--:-.:---:.--.:--.-:.-.:...:-:..-:...-:";
s=s".--:-..-:-.--:--..: ";
split(si,idx,"");
split(s,cipher,":");
for(i in idx) ci[idx[i]]=i;
splain="HELLO WORLD";
split(splain,plain,"");
for(i in plain) printf("%s ", cipher[ci[plain[i]]]);
print;
}
SIMPLE CALCULATOR
# echo 2 + 3 | awk -f 6.awk
{
z=0;
switch ($2) {
case "+" : z=$1+$3; break;
case "-" : z=$1-$3; break;
case "*" : z=$1*$3; break;
case "/" : z=$1/$3; break;
case "%" : z=$1%$3; break;
default : print "Illegal Operation",$2;
}
print $0," : ",$1,$2,$3,"=",z;
}
MULTIPLICATION TABLE FOR BASE 10
# echo 10 | awk -f 7.awk
{
printf(" :");
for(y=1;y<=$1-1;y++)
printf(" %d",y);
printf("\n");
printf("...");
for(y=1;y<=$1-1;y++)
printf(" ..");
printf("\n");
for(x=1;x<=$1-1;x++) {
printf("%d : ",x);
for(y=1;y<=$1-1;y++)
printf("%02d ",x*y);
printf("\n");
}
}
$ echo 10 | awk -f 7.awk
: 1 2 3 4 5 6 7 8 9
... .. .. .. .. .. .. .. .. ..
1 : 01 02 03 04 05 06 07 08 09
2 : 02 04 06 08 10 12 14 16 18
3 : 03 06 09 12 15 18 21 24 27
4 : 04 08 12 16 20 24 28 32 36
5 : 05 10 15 20 25 30 35 40 45
6 : 06 12 18 24 30 36 42 48 54
7 : 07 14 21 28 35 42 49 56 63
8 : 08 16 24 32 40 48 56 64 72
9 : 09 18 27 36 45 54 63 72 81
DELAY INTRODUCED
# echo 1010 1101 | awk -f this.awk
BEGIN {
print $1;
system("sleep 1.2");
print $2;
}
VALIDATE BOOLEAN
# echo false | awk -f 9.awk
{
x=$0;
x=x=="true"?1:x; x=x=="false"?0:x;
print x~/^(0|1)$/?"Ok":"NaB",x
}
VALIDATE INTEGER
# echo -1074 | awk -f 10.awk
{
print $0 ~ /^([+-]?[1-9][0-9]*|0)$/ ? "Ok" : "NaN",$0
}
VALIDATE REAL
# echo +1.074e-3 | awk -f 10.awk
{
print $0~/^([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)$/?"Ok":"NaN",$0
}
MORSE AND BACK. UNIX STYLE
$ cat lookup
A .-
B -...
C -.-.
D -..
E .
F ..-.
G --.
H ....
I ..
J .---
K -.-
L .-..
M --
N -.
O ---
P .--.
Q --.-
R .-.
S ...
T -
U ..-
V ...-
W .--
X -..-
Y -.--
Z --..
0 -----
1 .----
2 ..---
3 ...--
4 ....-
5 .....
6 -....
7 --...
8 ---..
9 ----.
$ cat lookup | awk '{print $2"\t"$1}' > rlookup
$ cat wrd
K
O
H
U
K
E
$ awk 'NR==FNR{a[$1]=$2;next} $1 in a {print a[$1]}' \
lookup wrd > rwrd
$ cat rwrd
-.-
---
....
..-
-.-
.
$ awk 'NR==FNR{a[$1]=$2;next} $1 in a {print a[$1]}' \
rlookup rwrd
K
O
H
U
K
E
https://stackoverflow.com/questions/9351902/how-can-i-get-the-length-of-an-array-in-awk
The way you introduce local variables in awk is as extra function parameters and the convention is to indicate this by adding extra spaces before these parameters.
ORS
-- The output record separator, by default a newline.
https://stackoverflow.com/questions/24331687/is-it-possible-to-print-the-awk-output-in-the-same-line
ord()
and chr()
in awk
https://www.gnu.org/software/gawk/manual/html_node/Ordinal-Functions.html
Initialize array in awk
https://stackoverflow.com/questions/14063783/how-to-initialize-an-array-of-arrays-in-awk
Use printf
instead of print
https://stackoverflow.com/questions/2021982/awk-without-printing-newline
Basic idea for example 6
Script explained step by step
https://stackoverflow.com/questions/32481877/what-are-nr-and-fnr-and-what-does-nr-fnr-imply