I'm currently working on a piece of code that assembles a string to identify an object based on various pieces of information. Some of that information might not always be available and I was wondering if there was clever way to make that assembly easier?
As an example we have the pieces $a, $b and $c that build the final identifier. Out of those $b might be empty and the final string should contain each components separated by a space. One option would be to add the additional space for $b to the string itself like this:
$a = "FirstPart"
$b = " SecondPart"
$c = "FinalPart"
Write-Output "$a$b $c"
#FirstPart SecondPart FinalPart
$b = ""
Write-Output "$a$b $c"
#FirstPart FinalPart
Another option would be to have a conditional (which can get rather complex and lengthy):
$a = "FirstPart"
$b = "SecondPart"
$c = "FinalPart"
if($b -eq ""){
Write-Output "$a $c"
}else{
Write-Output "$a $b $c"
#FirstPart SecondPart FinalPart
}
$b = ""
if($b -eq ""){
Write-Output "$a $c"
#FirstPart FinalPart
}else{
Write-Output "$a $b $c"
}
What actually would be quite need would be to use -join or maybe -f to get that conditional space if $b is not empty. Is there any way to do this or maybe another alternative? ($a,$b,$c) -join ' ' results in a double space if $b is empty.
$a = "FirstPart"
$b = "SecondPart"
$c = ""
$e = "last"
#put in array, and filter empty
$arr = ($a, $b, $c, $e) | ? { $_ }
#print in space separed
Write-Output "$arr"
Related
I saw some post already to do this but I didn't make it work. I would like to replace a string by an other at a specific line number in txt/csv file.
I have one file (that is supposed to update the second one with the new date)
"field1","date1","date2"
****,23/01/2018,03/04/2018
****,22/01/2018,03/04/2018
The second one (that is supposed to be older) :
"field1","date1","date2"
****,20/01/2018,03/04/2018
****,20/01/2018,03/04/2018
My script do the following :
Ask the user for a file to use to update the second asked file.So if there is a line match between some fields of the two files, I would like to update the "date1" by the "date1" of the first file.
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")
function Select-FileDialog
{
param([string]$Title,[string]$Directory,[string]$Filter="CSV File (*.csv)|*.csv")
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
$objForm = New-Object System.Windows.Forms.OpenFileDialog
$objForm.InitialDirectory = $Directory
$objForm.Filter = $Filter
$objForm.Title = $Title
$Show = $objForm.ShowDialog()
If ($Show -eq "OK")
{
Return $objForm.FileName
}
Else
{
Write-Error "Operation cancelled by user."
}
}
##Définition des variables
$ErrorActionPreference = "SilentlyContinue"
$dir = split-path -parent $MyInvocation.MyCommand.Definition
$base_file = Select-FileDialog -Title "Select a file" -Directory "$dir"
$bkp_file = "$dir\base.csv.bak"
##Make a backup of initial file
Copy-Item -Path "$final_file" -Destination "$bkp_file"
$final_file = Select-FileDialog -Title "Select a file" -Directory "$dir"
$import = Import-csv $base_file -Delimiter ";"
$tmpFile = "$dir\lineNumberOfMatches.txt"
$tmpFile2 = "$dir\newDates.txt"
foreach ($item in $import){
$source_base = $item.SOURCE
$pays_base = $item.PAYS
$symbo_base = $item.'SYMBO RZO'
$freq_base = $item.FREQUENCE
$periode_base = $item.PERIODE
$affectation_base = $item.AFFECTATION
$rang_base = $item.RANG
$indic_base = $item.INDICATIF
$ancienneSymbo_base = $item.'ANCIENNE SYMBO'
$modulation_base = $item.MODULATION
$datePerception_base = $item.'DATE PERCEPTION'
$dateMAJ_base = $item.'DATE MAJ'
$string = "$source_base;$pays_base;$symbo_base;$freq_base;$periode_base;$affectation_base;$rang_base;$indic_base;$ancienneSymbo_base;$modulation_base"
$match = Get-Content $final_file | Select-String -SimpleMatch "$string"
$new_date = $datePerception_base
echo $match.LineNumber >> $tmpFile #On met les lignes qui matchent et donc à remplacer dans le fichier de base pour changer la valeur plus tard
echo $new_date >> $tmpFile2
}
$i=0
##That's here that I need help
foreach ($line in Get-Content $tmpFile |sort -Unique){
$lineNumber = $line -1
$lineToChange = Get-Content $final_file | Select -Index ($lineNumber)
$old_date = echo $lineToChange | %{ $_.Split(';')[10]; }
$date = Get-Content $tmpFile2 | Select -Index $i
## I have the good results but can't place it at the right line number or overwrite the line
$lineToChange -replace "$old_date", "$date"
$i++
}
rm $tmpFile
rm $tmpFile2
It drives me crazy because I know with shell and sed the problem would be already solved... Thanks for reading and sorry for the long post !
PS : Don't look at the first import, I just take each field of the base file and put it in a variable to concatenate and make my string match with the other file
I finally succeed. I hope it could help someone...
##That's here that I need help
foreach ($line in Get-Content $tmpFile |sort -Unique){
$lineNumber = $line -1
$lineToChange = Get-Content $final_file | Select -Index ($lineNumber)
$old_date = echo $lineToChange | %{ $_.Split(';')[10]; }
$date = Get-Content $tmpFile2 | Select -Index $i
## I have the good results but can't place it at the right line number or overwrite the line
$lineToChange -replace "$old_date", "$date"
$i++
}
Replaced by :
$i=0
foreach ($line in Get-Content $tmpFile |sort -Unique){
$content = Get-Content $final_file
$lineNumber = $line -1
$lineToChange = Get-Content $final_file | Select -Index ($lineNumber)
#echo $lineToChange
$old_date = echo $lineToChange | %{ $_.Split(';')[10]; }
$date = Get-Content $tmpFile2 | Select -Index $i
$new_line = $lineToChange -replace "$old_date", "$date"
echo $new_line
for ($y = 0; $y -le ($content.Length -1); $y++){
if ($y -eq $lineNumber){
$content[$y] = $new_line
Set-Content $final_file $content
}
}
$i++
}
I am getting the error unary operator expected at line no 5 and line 11.
please help to resolve this problem.
echo ”enter the number”
read n
q=$n
a=0
while [ $q – gt 0 ]
do
r= `expr $q % 10 `
q= `expr $q / 10 `
a=`expr $a + $r /* $r /*$r `
done
if [ $a=$n ]
then
echo “the number $n is armstrong number”
else
echo “the number $n is not armstrong number”
fi
done
At line number 9 you have used the forward slash instead of backslash. Also the loop end should be above the 'if' condition. If condition also should be modified as -eq .
echo ”enter the number”
read n
q=$n
a=0
while [ $q -gt 0 ]
do
r=`expr $q % 10`
q=`expr $q / 10`
a=`expr $a + $r \* $r \* $r`
done
if [ $a -eq $n ]
then
echo “the number $n is armstrong number”
else
echo “the number $n is not armstrong number”
fi
I am a beginner in shell scripting.
Can anyone please tell me, what is the error in this code?
#!usr/bin/sh
#palindrome
echo "enter the number"
read a
len = ` echo $a | wc -c `
while [ $len -ne 0 ]
do
a1 = ` echo $a | cut -c $len `
rev = ${rev}${a1}
len = ` expr $len - 1 `
done
if [ $a == $rev ]
then
echo " palindrome"
else
echo "not a palindrome"
fi
#!usr/bin/sh # <-- This is probably not where `sh` is. You need the absolute path.
# sh is /bin/sh on many systems
#palindrome
echo "enter the number"
read a
len = ` echo $a | wc -c ` # <-- shell doesn't allow whitespace around assignments
# Do len=`echo $a | wc -c`
while [ $len -ne 0 ]
do
a1 = ` echo $a | cut -c $len `
rev = ${rev}${a1}
len = ` expr $len - 1 `
done
if [ $a == $rev ] # <-- use a single `=` sign.
then
echo " palindrome"
else
echo "not a palindrome"
fi
That's it for the functional issues. You may also consider:
Use "${#a}" to get the number of characters in the parameter a.
Use "${a: $x:$y}" to get a substring of the expansion of a.
Use $() instead of backticks for command substitution. It nests better.
Use read -p instead of echo …; read.
I am trying to find a way to replace the characters at the end of an array variable.. tried various ways and had no luck.. here is what I have
foreach ($File in $Files){
if ($File.EndsWith(".test"))
{
#Replaces test with EURTest at the end of the string
$File2 += $_ -replace "test", "EURTest"
}
elseif ($CanBeRemovedRoamingProfile.EndsWith("CTE"))
{
# Do nothing
$File2 += $File
}
else{
$File2 += $_ + '.Final'
}
}
Any idea ?
In...
$File2 += $_ -replace "test", "EURTest"
...and...
$File2 += $_ + '.Final'
...you're operating on the $_ variable. $_ would be used in the ForEach-Object cmdlet, whereas inside of a foreach loop you should use the loop variable, which is $File in this case.
In Powershell, how would you search each row in a text file for an array of patterns? Select-string's pattern can accept an array, but it returns a true value if any of the strings in the array are found. I need it to return true (or actually the lines) if ALL the strings in the array are found in the line. Thanks.
For matching an array of strings against an array of patterns I believe you need something like this:
$patterns = #( ... )
Get-Content sample.txt | % {
$count = 0
foreach ($p in $patterns) {
if ($_ -match $p) { $count++ }
}
if ($count -eq $patterns.Length) { $_ }
}
or like this:
$patterns = #( ... )
$content = Get-Content sample.txt
foreach ( $line in $content ) {
$count = #($patterns | ? { $line -match $_ }).Length
if ( $count -eq $patterns.Length ) { $line }
}
Off the top of my head
Get-Content file.txt |
Where-Object {$_ -match $ptrn1 -and $_ -match $ptrn2 -and $_ -match $ptrn3}
Another couple of possibilities:
$patterns = 'abc','def','ghi'
$lines = 'abcdefghi','abcdefg','abcdefghijkl'
:nextline foreach ($line in $lines)
{foreach ($pattern in $patterns)
{if ($line -notmatch $pattern){continue nextline}
}$line}
abcdefghi
abcdefghijkl
That will abandon further processing of a line as soon as any of the patterns fails to match.
This works on the entire line collection at once, rather that doing a foreach:
$patterns = 'abc','def','ghi'
$lines = 'abcdefghi','abcdefg','abcdefghijkl'
foreach ($pattern in $patterns)
{$lines = $lines -match $pattern}
$lines
abcdefghi
abcdefghijkl
Substitute your get-content for the test literals to populate $lines.