I have to make a script in shell and PowerShell that shortens ipv6 addresses as much as possible.
Like:
Input: 2001:0db8:03cd:0000:0000:ef45:0006:0123
Output: 2001:db8:3cd:::ef45:6:123
And the script should give a description of itself if -help parameter used but i dont know how to do that in PowerShell.
This is my code in PowerShell, it shortens the addresses correctly:
param([parameter(Mandatory=$true)]$file)
if (test-path $file){
foreach ($ip in Get-Content $file){
$ip=$ip.Replace("0000","")
Write-Host $ip
}
}
I have no idea how to do the shortening in shell, I tried like this but didn't work:
#!/bin/sh
if [ $1 = "-help" ]
then
echo description
else file = $1
fi
for ip in `cat ipv6.txt`
do
$ip=$line
$replace=""
$echo ${var//0000/$replace}
done
This is the txt file with the addresses:
http://uptobox.com/6woujdvdfkmh
The beauty of PowerShell is that you have access to a rich library that has methods for doing this for you. Try this:
<#
.SYNOPSIS
Converts long form IP address into its short form
.DESCRIPTION
Converts long form IP address into its short form
.PARAMETER IPAddress
The IP address to convert.
.EXAMPLE
PS C:\> ConvertTo-IPAddressCompressedForm 2001:0db8:03cd:0000:0000:ef45:0006:0123
#>
function ConvertTo-IPAddressCompressedForm($IPAddress) {
[System.Net.IPAddress]::Parse($IPAddress).IPAddressToString
}
C:\> ConvertTo-IPAddressCompressedForm 2001:0db8:03cd:0000:0000:ef45:0006:0123
2001:db8:3cd::ef45:6:123
Note that to get usage in PowerShell based on the doc comments use:
ConvertTo-IPAddressCompressedForm -?
We might be going to the same school. This is what I was told to do and it works perfectly:
cat filename | sed -e 's/:0*/:/g' filename
$longIPAddress = '2001:0db8:03cd:0000:0000:ef45:0006:0123'
$shortIPAddress = ([IPAddress]$longIPAddress).IPAddressToString
$shortIPAddress
2001:db8:3cd::ef45:6:123
Related
I have a PowerShell script (which I cannot change) with the following function inside it:
function Foo ([string] param1) {
[...]
$var1 = Read-Host "Test"
$var2 = Read-Host "Test2"
[...]
}
I want to call the function from my PowerShell script and want to prevent that the user has to input any values, instead I want to prepare hardcoded values.
I tried the following:
#("Var1Value", "Var2Value") | Foo "Param1Value"
But it still prompts the user. Any ideas?
During command discovery, functions take precedence over binary cmdlets, so you can "hide" Read-Host behind a fake Read-Host function:
# define local Read-Host function
function Read-Host {
param([string]$Prompt)
return #{Test = 'Var1Value'; Test2 = 'Var2Value'}[$Prompt]
}
# call foo
foo
# remove fake `Read-Host` function again
Remove-Item function:\Read-Host -Force
I have an interesting problem that I can't seem to find the answer for. I am creating a simple app that will help my dev department auto launch docker containers with NginX and config files. My problem is, for some reason I can't get the bash script to store the name of a folder, while scanning the directory. Here is an extremely simple example of what I am talking about....
#!/bin/bash
getFolder() {
local __myResultFolder=$1
local folder
for d in */ ; do
$folder=$d
done
__myResultFolder=$folder
return $folder
}
getFolder FOLDER
echo "Using folder: $FOLDER"
I then save that simple script as folder_test.sh and put it in a folder where there is only one folder, change owner to me, and give it correct permissions. However, when I run the script I keep getting the error...
./folder_test.sh: 8 ./folder_test.sh: =test_folder/: not found
I have tried putting the $folder=$d part in different types of quotes, but nothing works. I have tried $folder="'"$d"'", $folder=`$d`, $folder="$d" but none of it works. Driving me insane, any help would be greatly appreciated. Thank you.
If you want to save your result into a named variable, what you're doing is called "indirect assignment"; it's covered in BashFAQ #6.
One way is the following:
#!/bin/bash
# ^^^^ not /bin/sh; bash is needed for printf -v
getFolder() {
local __myResultFolder=$1
local folder d
for d in */ ; do
folder=$d
done
printf -v "$__myResultFolder" %s "$folder"
}
getFolder folderName
echo "$folderName"
Other approaches include:
Using read:
IFS= read -r -d '' "$__myResultFolder" < <(printf '%s\0' "$folder")
Using eval (very, very carefully):
# note \$folder -- we're only trusting the destination variable name
# ...not trusting the content.
eval "$__myResultFolder=\$folder"
Using namevars (only if using new versions of bash):
getFolder() {
local -n __myResultFolder=$1
# ...your other logic here...
__myResultFolder=$folder
}
The culprit is the line
$folder=$d
which is treating the folder names to stored with a = sign before and tried to expand it in that name i.e. literally treats the name =test_folder/ as an executable to be run under shell but does not find a file of that name. Change it to
folder=$d
Also, bash functions' return value is only restricted to integer types and you cannot send a string to the calling function. If you wanted to send a non-zero return code to the calling function on $folder being empty you could add a line
if [ -z "$folder" ]; then return 1; else return 0; fi
(or) if you want to return a string value from the function, do not use return, just do echo of the name and use command-substitution with the function name, i.e.
getFolder() {
local __myResultFolder=$1
local folder
for d in */ ; do
folder=$d
done
__myResultFolder=$folder
echo "$folder"
}
folderName=$(getFolder FOLDER)
echo "$folderName"
I have an issue changing an script I did in bash to powershell, the script is the following:
#! /bin/sh
for IPVAR in 172.27.41.202 172.27.41.203
do
TIEMPO=$(date +"%m-%d-%y")
FILENAME=${IPVAR}_${TIEMPO}
date +"%c" >> $FILENAME.txt
snmpget -v 2c -c public $IPVAR -mALL 1.3.6.1.4.1.41413.1.1.0 1.3.6.1.4.1.41413.1.4.0 1.3.6.1.4.1.41413.1.2.0 1.3.6.1.4.1.41413.1.3.0 1.3.6.1.4.1.41413.10.3.4.1.1.1 1.3.6.1.4.1.41413.10.3.4.1.2.1 1.3.6.1.4.1.41413.10.3.4.1.3.1 1.3.6.1.4.1.41413.10.3.4.1.4.1 1.3.6.1.4.1.41413.10.3.4.1.5.1 1.3.6.1.4.1.41413.10.3.4.1.6.1 1.3.6.1.4.1.41413.10.3.4.1.7.1 1.3.6.1.4.1.41413.10.3.4.1.8.1 1.3.6.1.4.1.41413.10.3.4.1.9.1 1.3.6.1.4.1.41413.10.3.4.1.10.1 >> $FILENAME.txt
done
In my Linux enviroment works fine but I installed NET-SNMP in a Windows Server because there is where we need the files to be but I can seem to make it work I did this:
$IPS = (10.96.90.2)
$TIEMPO = get-date -f yyyy-MM-dd
Foreach ($IPVAR in $IPS) {snmpget -v 2c -c public -m ALL $IPVAR 1.3.6.1.4.1.41413.1.1.0 1.3.6.1.4.1.41413.1.4.0 1.3.6.1.4.1.41413.1.2.0 1.3.6.1.4.1.41413.1.3.0 1.3.6.1.4.1.41413.10.3.4.1.1.1 1.3.6.1.4.1.41413.10.3.4.1.2.1 1.3.6.1.4.1.41413.10.3.4.1.3.1 1.3.6.1.4.1.41413.10.3.4.1.4.1 1.3.6.1.4.1.41413.10.3.4.1.5.1 1.3.6.1.4.1.41413.10.3.4.1.6.1 1.3.6.1.4.1.41413.10.3.4.1.7.1 1.3.6.1.4.1.41413.10.3.4.1.8.1 1.3.6.1.4.1.41413.10.3.4.1.9.1 1.3.6.1.4.1.41413.10.3.4.1.10.1 >> "$IPVAR_$TIEMPO".txt}
If I run only the "snmpget" command it works fine but I have troubles with the scripting part here.
Hope you can help me.
Regards,
Try the code below (this hasn't been tested as I don't have snmpget, but the method works with other command line apps):
$IPS = #('172.27.41.202', '172.27.41.203')
$IPS | ForEach-Object {
$snmpgetParams = #(
'-v', '2c' ,'-c' ,'public' ,'-m' ,'ALL', $_, '1.3.6.1.4.1.41413.1.1.0 1.3.6.1.4.1.41413.1.4.0 1.3.6.1.4.1.41413.1.2.0 1.3.6.1.4.1.41413.1.3.0 1.3.6.1.4.1.41413.10.3.4.1.1.1 1.3.6.1.4.1.41413.10.3.4.1.2.1 1.3.6.1.4.1.41413.10.3.4.1.3.1 1.3.6.1.4.1.41413.10.3.4.1.4.1 1.3.6.1.4.1.41413.10.3.4.1.5.1 1.3.6.1.4.1.41413.10.3.4.1.6.1 1.3.6.1.4.1.41413.10.3.4.1.7.1 1.3.6.1.4.1.41413.10.3.4.1.8.1 1.3.6.1.4.1.41413.10.3.4.1.9.1 1.3.6.1.4.1.41413.10.3.4.1.10.1'
)
$TIEMPO = Get-Date -f yyyy-MM-dd
$FILENAME="$_`_$TIEMPO`.txt"
snmpget #snmpgetParams | Set-Content $FILENAME -Force
}
Line 1 declares an array of IP addresses.
Line 2 starts a foreach loop which will iterate through each IP in the $IPS array.
Lines 3,4,5 create an array of parameters to pass to the snmpget command. The $_ parameter is the current IP address within the loop.
Line 7 sets the $TIEMPO variable with the date.
Line 8 sets the $FILENAME variable with the IP address, followed by an underscore, followed by the date. The backticks ` tell PowerShell to not treat the following characters as part of the preceding variable name. An example filename: 172.27.41.202_2016-08-31.txt
Line 10 calls the snmpget command. The #snmpgetParams 'splats' the parameter array. The output is piped into the Set-Content command, which, with the Force option creates or overwrites the file contents for that IP & date.
Line 11 closes the loop.
I'm trying to write a custom prompt for PowerShell and I was wondering how I would filter out the 1...n directories in the output of Get-Location.
function prompt {
"PS " + $(get-location) + "> "
}
So, if the path is too long I would like to omit some of the directories and just display PS...blah\blah> or something. I tried (get-container) - 1 but it doesn't work.
Use Split-Path with the -Leaf parameter if you want just the last element of a path:
function prompt {
"PS {0}> " -f (Split-Path -Leaf (Get-Location))
}
I wanted to make a more dynamic function. I do just basic string manipulation. You could do some logic nesting Split-Path but the string manipulation approach is just so much more terse. Since what you want to be returned wont be a fully validated path I feel better offering this solution.
Function Get-PartialPath($path, $depth){
If(Test-Path $path){
"PS {0}>" -f (($path -split "\\")[-$depth..-1] -join "\")
} else {
Write-Warning "$path is not a valid path"
}
}
Sample Function call
Get-PartialPath C:\temp\folder1\sfg 2
PS folder1\sfg>
So you can use this simple function. Pass is a string for the path. Assuming it is valid then it will carve up the path into as many trailing chunks as you want. We use -join to rebuild it. If you give a $depth number that is too high the whole path will be returned. So if you only wanted to have 3 folders being shown setting the $depth for 3.
Ansgar Wiechers' answer will give you the last directory but if you want a way to do multiple directories at the end of the filepath (using the triple dot notation) you can cast the directory path to a uri and then just get and join the segments:
function prompt {
$curPath = pwd
$pathUri = ([uri] $curPath.ToString())
if ($pathUri.Segments.Count -le 3) {
"PS {0}>" -f $curPath
} else {
"PS...{0}\{1}>" -f $pathUri.Segments[-2..-1].trim("/") -join ""
}
}
Or using just a string (no uri cast)
function prompt {
$curPath = pwd
$pathString = $curPath.Tostring().split('\') #Changed; no reason for escaping
if ($pathString.Count -le 3) {
"PS {0}>" -f $curPath
} else {
"PS...{0}\{1}>" -f $pathString[-2..-1] -join ""
}
}
$a = prompt
Write-Host $a
Then just change -2 to whatever you want to be the first directory and -le 3 to match. I typically use the uri cast when I have to run stuff through a browser or over connections to Linux machines (as it uses "/" as a path separator) but there is no reason to not use the string method for normal operations.
Does anybody know how to determine the location of a file that's in one of the folders specified by the PATH environmental variable other than doing a dir filename.exe /s from the root folder?
I know this is stretching the bounds of a programming question but this is useful for deployment-related issues, also I need to examine the dependencies of an executable. :-)
You can use the where.exe utility in the C:\Windows\System32 directory.
For WindowsNT-based systems:
for %i in (file) do #echo %~dp$PATH:i
Replace file with the name of the file you're looking for.
If you want to locate the file at the API level, you can use PathFindOnPath. It has the added bonus of being able to specify additional directories, in case you want to search in additional locations apart from just the system or current user path.
On windows i'd say use %WINDIR%\system32\where.exe
Your questions title doesn't specify windows so I imagine some folks might find this question looking for the same with a posix OS on their mind (like myself).
This php snippet might help them:
<?php
function Find( $file )
{
foreach( explode( ':', $_ENV( 'PATH' ) ) as $dir )
{
$command = sprintf( 'find -L %s -name "%s" -print', $dir, $file );
$output = array();
$result = -1;
exec( $command, $output, $result );
if ( count( $output ) == 1 )
{
return( $output[ 0 ] );
}
}
return null;
}
?>
This is slightly altered production code I'm running on several servers. (i.e. taken out of OO context and left some sanitation and error checking out for brevity.)
Using PowerShell on Windows...
Function Get-ENVPathFolders {
#.Synopsis Split $env:Path into an array
#.Notes
# - Handle 1) folders ending in a backslash 2) double-quoted folders 3) folders with semicolons 4) folders with spaces 5) double-semicolons i.e. blanks
# - Example path: 'C:\WINDOWS\;"C:\Path with semicolon; in the middle";"E:\Path with semicolon at the end;";;C:\Program Files;
# - 2018/01/30 by Chad#ChadsTech.net - Created
$NewPath = #()
$env:Path.ToString().TrimEnd(';') -split '(?=["])' | ForEach-Object { #remove a trailing semicolon from the path then split it into an array using a double-quote as the delimeter keeping the delimeter
If ($_ -eq '";') { # throw away a blank line
} ElseIf ($_.ToString().StartsWith('";')) { # if line starts with "; remove the "; and any trailing backslash
$NewPath += ($_.ToString().TrimStart('";')).TrimEnd('\')
} ElseIf ($_.ToString().StartsWith('"')) { # if line starts with " remove the " and any trailing backslash
$NewPath += ($_.ToString().TrimStart('"')).TrimEnd('\') #$_ + '"'
} Else { # split by semicolon and remove any trailing backslash
$_.ToString().Split(';') | ForEach-Object { If ($_.Length -gt 0) { $NewPath += $_.TrimEnd('\') } }
}
}
Return $NewPath
}
$myFile = 'desktop.ini'
Get-ENVPathFolders | ForEach-Object { If (Test-Path -Path $_\$myFile) { Write-Output "Found [$_\$myFile]" } }
I also blogged the answer with some details over at http://blogs.catapultsystems.com/chsimmons/archive/2018/01/30/parse-envpath-with-powershell
In addition to the 'which' (MS Windows) and 'where' (unix/linux) utilities, I have written my own utility which I call 'findinpath'. In addition to finding the executable that would be executed, if handed to the command line interpreter (CLI), it will find all matches, returned path-search-order so you can find path-order problems. In addition, my utility returns not just executables, but any file-specification match, to catch those times when a desired file isn't actually executable.
I also added a feature that has turned out to be very nifty; the -s flag tells it to search not just the system path, but everything on the system disk, known user-directories excluded. I have found this feature to be incredibly useful in systems administration tasks...
Here's the 'usage' output:
usage: findinpath [ -p <path> | -path <path> ] | [ -s | -system ] <file>
or findinpath [ -h | -help ]
where: <file> may be any file spec, including wild cards
-h or -help returns this text
-p or -path uses the specified path instead of the PATH environment variable.
-s or -system searches the system disk, skipping /d /l/ /nfs and /users
Writing such a utility is not hard and I'll leave it as an exercise for the reader. Or, if asked here, I'll post my script - its in 'bash'.
just for kicks, here's a one-liner powershell implementation
function PSwhere($file) { $env:Path.Split(";") | ? { test-path $_\$file* } }