Bash-style escape-underscore in Powershell - powershell

In bash I frequently use the escape underscore shortcut:
subl somedir/file.sh
./(escape underscore)
Which fills in the last item from the last line, eg:
./(escape underscore)
Becomes:
./somedir/file.sh
Is there a way I could set this up in powershell?
(I'm using Powershell 5.1, ConEmu, and PSReadLine and PCSX)

If you use Emacs mode with PSReadline, then Esc underscore does the right thing. Alt+. also does the same thing and is bound in both Emacs and Windows modes.

I don't know a similar function in Powershell (maybe just create one by yourself?), but you could go with an array. For example:
(Get-Childitem somedir)[-1]
It's not the same, but maybe a solution you could go with.

Another option is using Select-Object:
The Long version:
Get-ChildItem | Select-Object -Last 1
The short:
ls | select -l 1

Related

Awk command to Powershell equivalent

I hope can you help me, essentially, I'm looking for the Powershell equivalent of the awk command:
awk '/"Box11"/ { print $0 }' test.txt|awk '{ SUM += $4} END { print SUM} '
What his does is print lines that contain the string Box11, then piping it to another awk that prints the total of the 4th column (delimited by spaces).
Multiple ways of doing it but this would do the trick:
Get-Content c:\temp\test.txt | Where-Object{$_ -match '"Box11"'} |
ForEach-Object{($_ -split "\s+")[3]} | Measure-Object -Sum |
Select-Object -ExpandProperty Sum
Get a string array of the file. For each line that contains the string "Box11" we split the line on each group of spaces. Then pass the 4 element of each match to Measure-Object.
A short hand, if you value that, would look like this:
gc c:\temp\test.txt | ?{$_ -match '"Box11"'} | %{($_ -split "\s+")[3]} |
Measure -Sum | Select -Exp Sum
If this file/string input had header this would be a good start as well. Assuming of course that your file is delimited with one space exactly.
Get-Content c:\temp\test.txt | ConvertFrom-Csv -Delimiter " "
I know this post is old but i thought I'd add to this. Currently if yo have WSL (windows sub system for Linux) enabled, (windows 10 all version on systems that support virtualization, in the turn windows features on) with a distribution installed in the subsystem. You can can call Linux commands directly from windows
wsl -e awk '/"Box11"/{sum += $4} END{print sum}' test.txt
(borrowed from #Ed Moritn)
( or any awk command of your choice. )
Basically cmd or PowerShell takes the command and pipes it into the subsystem and the results are returned (bit of an over simplification but in effect accurate). But the -e flag allows you to execute the command without opening an instance.
edit
Since writing this initial response I have found two answers which are better solutions. The first is GNUwin32 This is a collection of Gnutils which have been ported to windows standalone .exe files including sed, awk, grep and many more, allowing you to call get-childitem | awk.exe '{print $1}' directly. These tools are fully portable with no installation required. The second option is Msys32, a platform that grew out of chocolatey (though it is almost fully code in dependant now) designed for cross compiling binaries. Once installed in the /bin folder, are many Linux utilities as exe files. most of these executable can be pulled from the bin and are portable with no required installation of dependencies. The reason msys32 is preferred (in my books) over the gnuwin32 is the fact that that gnuwin32 has gawk version 3.1 and msys32 has nawk and gawk vs 5.1.
You can get get awk for Windows now. I have been using it as a direct replacement and haven't had any problems yet.
It can be easily installed via Chocolatey

How do I remove or replace a built in alias in powershell?

Powershell includes a built-in alias diff for the Compare-Object cmdlet. This is really annoying for me, as I'm used to using the Unix diff command.
Is there a way to remove the built in diff alias, or otherwise override it?
I've tried:
del alias:diff - gives an error "Alias was not removed because alias diff is constant or read-only"
set-alias diff diff.exe - gives an error similar to the above
function diff { diff.exe $args } - the alias takes precedence
How do I get access to the "real" diff (without having to remember a different name)?
In case it matters, this is Powershell 3. I haven't tried it in version 4 yet, although version 4 also has a wget alias, but unlike diff I could remove that one...
Try removing if forcefully.
del alias:diff -Force
For Windows 10 1803 build 17134 it only removes a constant alias for the current window even if -Force is used.
in certain cases, the -option is required
Set-Alias 'type' 'read-host' -force -option 'Constant','AllScope'
Win10 19xxx

How do I reference variables when executing a shell command in PowerShell?

I'm a newbie to PowerShell. What's wrong with my script below? It's not wanting to emit the value of $config. However, when I wrap that command in double quotes, everything looks okay.
param($config, $logfolder)
# Must run log analysis in chronological order.
ls $logfolder | Sort-Object LastWriteTime | % {
perl D:\Websites\_awstats\wwwroot\cgi-bin\awstats.pl -LogFile="$($_.FullName)" -config=$config update
}
# Execute with - .\regen-logs.ps1 webgenesis "C:\inetpub\logs\LogFiles\W3SVC5"
# Returns for each file - Error: Couldn't open config file "awstats.config.conf" nor "awstats.conf" after searching in path "D:\Websites\_awstats\wwwroot\cgi-bin,/etc/awstats,/usr/local/etc/awstats,/etc,/etc/opt/awstats": No such file or directory
As-is, what gets emitted and executed seems to have "-config=$config" passed as an argument. At least, that's my best guess. I don't know if $_ is working correctly either.
If I put quotes around the perl command like so, I get the command I do want to execute.
ls $logfolder | Sort-Object LastWriteTime | % {
"perl D:\Websites\_awstats\wwwroot\cgi-bin\awstats.pl -LogFile=`"$($_.FullName)`" -config=$config update"
}
# Outputs for each log file something like - perl D:\Websites\_awstats\wwwroot\cgi-bin\awstats.pl -LogFile="C:\inetpub\logs\LogFiles\W3SVC5\u_ex110602.log" -config=webgenesis update
If putting quotes around it produces the correct commandline, one way to execute the contents of a string is with Invoke-Expression (alias iex):
$v = "myexe -myarg1 -myarg2=$someVar"
iex $v
Put double quotes around "-config=$config". Without this, PowerShell will interpret -config=$config as one string argument that just happens to contain a $ sign in it.
I think you need to start your perl command out with & so that PowerShell interprets things as a command and not a string.
& perl D:\Websites\_awstats\wwwroot\cgi-bin\awstats.pl -LogFile=`"$($_.FullName)`" -config=$config update
Also, see: Run a program in a foreach

Translate a Unix1Liner to PowerShell

I would like to translate the following Unix 1 Liner to PowerShell.
Synopsis of the command:
This command will search recursively form the PWD (pressent working directory) for any file with the extenstion .jsp, and look inside the file for a simple string match of 'logoutButtonForm'. If it finds a match, it will print the file name and the text that it matched.
find . -name "*.jsp" -exec grep -aH "logoutButtonForm" {}\;
I am new to power shell and have done some googling/binging but have not found a good answer yet.
ls . -r *.jsp | Select-String logoutButtonForm -case
I tend to prefer -Filter over -Include. Guess I never trusted the -Exclude/-Include parameters after observing buggy behavior in PowerShell 1.0. Also, -Filter is significantly faster than using -Include.

Parsing to simulate "grep -C 2" in PowerShell version 1.0

I'm trying to dig through some logs and need information before and after the line I can match on. How would I do this in PowerShell ala "grep -C 2"?
In version 1, I can't wait for r2, then I get to put it on production machines :)
The PowerShell equivalent of grep is select-string. You can use the following.
cat file | select-string "pattern" -context 2
Note: this works in PowerShell v2.0 only.
Instead of using (gc $bigfile) again, which will cause PowerShell to read in $bigfile to memory on every object piped to it by the ForEach-Object cmdlet, you should probably read the file into a variable and then array index from that, like so:
$bigfile = gc 'c:\scripts\bigfile.txt'
$bigfile | Select-String "melissao" | % {$bigfile[($_.LineNumber -3)..($_.LineNumber +1)]}
Also, since the line numbering starts at 1 and array indexing starts at 0 you'll have to go backwards by 3, not 2, to get the line two spaces above "melissao", and go forwards by 1, not 2, to get the line two spaces below "melissao." Doing this will net you the 5 lines you want, "melissao" flanked by the two lines above and below it.
I'm not super familiar with grep -C 2, so I don't know if this replicates that functionality exactly.
Alas, it looks like you will have to build it yourself or wait for the next version of powershell, as it seems to have been implemented there. You can download a pre-release version of Powershell 2.0 from here.
Getting closer here- because Select-String returns MatchInfo objects which I can pull a line number out of (39017), now I just need to pull the line surrounding... so:
gc $bigfile | Select-String melissao |
%{(gc $bigfile)[($_.LineNumber -2)..($_.LineNumber +2)]}
If anyone could clean this up a bit to make it less slow, you may have the answer. Otherwise, this solution works but obviously not quickly.
Download grep for Windows, and call grep from PowerShell?