Dizelerdeki değişken değiştirme hakkında bilmek istediğiniz her şey

Dizelerde değişkenleri kullanmanın birçok yolu vardır. Bu değişkeni değiştirme olarak adlandırıyorum ancak bir dizeyi değişkenlerden değerleri içerecek şekilde biçimlendirmek istediğiniz her zaman ifade ediyorum. Bu sık sık yeni betikçilere açıklama yaptığım bir şey.

Uyarı

Bu makalenin özgün sürümü, @KevinMarquette tarafından yazılan blogda yer almıştır. PowerShell ekibi, bu içeriği bizimle paylaştığı için Kevin'e teşekkür ederiz. Lütfen PowerShellExplained.com'daki blogunu inceleyin.

Birleştirme

Yöntemlerin ilk sınıfı birleştirme olarak adlandırılabilir. Temel olarak birkaç dize alıp bunları birleştirmektir. Biçimlendirilmiş dizeler oluşturmak için birleştirme kullanmanın uzun bir geçmişi vardır.

$name = 'Kevin Marquette'
$message = 'Hello, ' + $name

Birleştirme, eklenecek yalnızca birkaç değer olduğunda tamam olur. Ancak bu hızla karmaşık bir hal alabilir.

$first = 'Kevin'
$last = 'Marquette'
$message = 'Hello, ' + $first + ' ' + $last + '.'

Bu basit örnek zaten okunmasını zorlaştırıyor.

Değişken değiştirme

PowerShell'in daha kolay bir seçeneği daha vardır. Değişkenlerinizi doğrudan dizelerde belirtebilirsiniz.

$message = "Hello, $first $last."

Dizenin çevresinde kullandığınız tırnak işaretleri türü bir fark yaratır. Çift tırnak içine alınmış bir dize, değişime izin verir, ancak tek bir tırnak içine alınmış dize izin vermez. Bazen birini veya diğerini istediğiniz zamanlar vardır, bu nedenle bir seçeneğiniz vardır.

Komut değiştirme

Özelliklerin değerlerini bir dizeye almaya çalıştığınızda işler biraz karmaşık olur. Burası birçok yeni insanın tökezlediği yer. İlk olarak size nelerin çalışması gerektiğini düşündüklerini göstereyim (ve yüz değerinde neredeyse olması gerektiği gibi görünür).

$directory = Get-Item 'C:\windows'
$message = "Time: $directory.CreationTime"

değerini almayı CreationTime$directorybekliyor olabilirsiniz, ancak bunun yerine değeriniz olarak bunu Time: C:\windows.CreationTime alırsınız. Bunun nedeni, bu tür bir değiştirmenin yalnızca temel değişkeni görmesidir. Dönemi dizenin bir parçası olarak kabul eder, bu nedenle değeri daha derin çözümlemeyi durdurur.

Bu nesne bir dizeye yerleştirildiğinde bir dizeyi varsayılan değer olarak verir. Bazı nesneler size gibi System.Collections.Hashtabletür adı verir. Sadece izleyebileceğiniz bir şey.

PowerShell, özel bir söz dizimi ile dize içinde komut yürütme gerçekleştirmenizi sağlar. Bu, bu nesnelerin özelliklerini almamıza ve değer almak için başka bir komut çalıştırmamıza olanak tanır.

$message = "Time: $($directory.CreationTime)"

Bu, bazı durumlarda harika çalışır, ancak yalnızca birkaç değişkeniniz varsa birleştirme kadar çılgın olabilir.

Komut yürütme

Komutları bir dize içinde çalıştırabilirsiniz. Bu seçeneğim olsa da, bundan hoşlanmıyorum. Hızlı bir şekilde dağınık hale gelir ve hata ayıklaması zorlaşır. Komutunu çalıştırıp bir değişkene kaydediyorum veya bir biçim dizesi kullanıyorum.

$message = "Date: $(Get-Date)"

Dizeyi biçimlendir

.NET'in, çalışmayı oldukça kolay bulduğum dizeleri biçimlendirmek için bir yolu var. İlk olarak, aynı şeyi yapmak için PowerShell kısayolunu göstermeden önce bunun statik yöntemini göstereyim.

# .NET string format string
[string]::Format('Hello, {0} {1}.',$first,$last)

# PowerShell format string
'Hello, {0} {1}.' -f $first, $last

Burada olan, dizenin belirteçler {0} ve için ayrıştırılmış olmasıdır ve {1}sağlanan değerlerden seçmek için bu sayıyı kullanır. Dizede bir değer yinelemek istiyorsanız, bu değer numarasını yeniden kullanabilirsiniz.

Dize ne kadar karmaşık olursa, bu yaklaşımdan o kadar fazla değer elde edersiniz.

Değerleri dizi olarak biçimlendirme

Biçim çizginiz çok uzun olursa, önce değerlerinizi bir diziye yerleştirebilirsiniz.

$values = @(
    "Kevin"
    "Marquette"
)
'Hello, {0} {1}.' -f $values

Tüm diziyi geçtiğim için bu sıçrama değil, ama fikir benzer.

Gelişmiş biçimlendirme

Üzerinde zaten iyi belgelenmiş birçok biçimlendirme seçeneği olduğundan bunları kasıtlı olarak .NET'ten geliyor olarak adlandırdım. Çeşitli veri türlerini biçimlendirmenin yerleşik yolları vardır.

"{0:yyyyMMdd}" -f (Get-Date)
"Population {0:N0}" -f  8175133
20211110
Population 8,175,133

Onlara girmeyeceğim ama ihtiyacınız olursa bunun çok güçlü bir biçimlendirme altyapısı olduğunu size bildirmek istedim.

Dizeleri birleştirme

Bazen aslında bir değer listesini bir araya getirmek istersiniz. Bunu sizin için yapabilecek bir -join operatör var. Hatta dizeler arasında birleştireceğiniz bir karakter belirtmenize de olanak tanır.

$servers = @(
    'server1'
    'server2'
    'server3'
)

$servers  -join ','

Ayırıcı içermeyen bazı dizeler istiyorsanız -join , boş bir dize ''belirtmeniz gerekir. Ancak ihtiyacınız olan tek şey buysa, daha hızlı bir seçenek vardır.

[string]::Concat('server1','server2','server3')
[string]::Concat($servers)

Ayrıca dizeleri de -split kullanabileceğinizi belirtmek gerekir.

Join-Path

Bu genellikle göz ardı edilir, ancak dosya yolu oluşturmak için harika bir cmdlet'dir.

$folder = 'Temp'
Join-Path -Path 'C:\windows' -ChildPath $folder

Bunun en iyi özelliği, değerleri bir araya getirirken ters eğik çizgilerin doğru şekilde çalışmasıdır. Bu, özellikle kullanıcılardan veya yapılandırma dosyalarından değer alıyorsanız önemlidir.

Bu, ve Test-Pathile Split-Path de iyi gider. Ayrıca, dosyaları okuma ve dosyalara kaydetme hakkındaki gönderimde bunları da ele alıyorum.

Dizeler dizilerdir

Devam etmeden önce buraya dize eklemeden bahsetmem gerekiyor. Dizenin yalnızca bir karakter dizisi olduğunu unutmayın. Birden çok dizeyi bir araya eklediğinizde, her seferinde yeni bir dizi oluşturulur.

Şu örneğe bakın:

$message = "Numbers: "
foreach($number in 1..10000)
{
    $message += " $number"
}

Çok basit görünüyor ama bu dizeye her yeni dize eklendiğinde $message bu dizeyi görmüyorsunuz. Bellek ayrılır, veriler kopyalanır ve eskisi atılır. Yalnızca birkaç kez yapıldığında önemli değildir, ancak bunun gibi bir döngü sorunu gerçekten ortaya çıkarır.

StringBuilder

StringBuilder, çok sayıda küçük dizeden büyük dizeler oluşturmak için de çok popülerdir. Bunun nedeni, yalnızca ona eklediğiniz tüm dizeleri toplaması ve yalnızca değeri aldığınızda bunların tümünü sonunda birleştirmesidir.

$stringBuilder = New-Object -TypeName "System.Text.StringBuilder"

[void]$stringBuilder.Append("Numbers: ")
foreach($number in 1..10000)
{
    [void]$stringBuilder.Append(" $number")
}
$message = $stringBuilder.ToString()

Bu da .NET'e ulaşmak istediğim bir şey. Artık sık kullanmıyorum ama orada olduğunu bilmek güzel.

Ayraçlarla çizgi çizme

Bu, dize içindeki sonek birleştirme için kullanılır. Bazen değişkeninizin temiz bir sözcük sınırı yoktur.

$test = "Bet"
$tester = "Better"
Write-Host "$test $tester ${test}ter"

Bunun için teşekkür ederim Redditor u/real_parbold .

Bu yaklaşımın alternatifi aşağıda verilmiştir:

Write-Host "$test $tester $($test)ter"
Write-Host "{0} {1} {0}ter" -f $test, $tester

Bunun için kişisel olarak biçim dizesi kullanıyorum, ancak bunu vahşi doğada görmeniz durumunda bunu bilmek iyi olur.

Belirteçleri bulma ve değiştirme

Bu özelliklerin çoğu kendi çözümünüzü dağıtma gereksiniminizi sınırlasa da, içinde dizeleri değiştirmek istediğiniz büyük şablon dosyalarına sahip olabileceğiniz zamanlar olabilir.

Çok fazla metin içeren bir dosyadan şablon çektiğinizi varsayalım.

$letter = Get-Content -Path TemplateLetter.txt -RAW
$letter = $letter -replace '#FULL_NAME#', 'Kevin Marquette'

Değiştirebilecek çok sayıda belirteciniz olabilir. İşin püf noktası, bulunması ve değiştirilmesi kolay çok farklı bir belirteç kullanmaktır. Ayırt etmek için her iki uçta da özel bir karakter kullanma eğilimindeyim.

Yakın zamanda buna yaklaşmak için yeni bir yol buldum. Bu bölümü burada bırakmaya karar verdim çünkü bu yaygın olarak kullanılan bir desendir.

Birden çok belirteci değiştirme

Değiştirmem gereken belirteçlerin listesi olduğunda daha genel bir yaklaşım benimserim. Bunları bir karma tabloya yerleştirir ve değiştirme işlemini yapmak için yinelerdim.

$tokenList = @{
    Full_Name = 'Kevin Marquette'
    Location = 'Orange County'
    State = 'CA'
}

$letter = Get-Content -Path TemplateLetter.txt -RAW
foreach( $token in $tokenList.GetEnumerator() )
{
    $pattern = '#{0}#' -f $token.key
    $letter = $letter -replace $pattern, $token.Value
}

Gerekirse bu belirteçler JSON veya CSV'den yüklenebilir.

ExecutionContext ExpandString

Tek tırnaklı bir değiştirme dizesi tanımlamanın ve değişkenleri daha sonra genişletmenin akıllıca bir yolu vardır. Şu örneğe bakın:

$message = 'Hello, $Name!'
$name = 'Kevin Marquette'
$string = $ExecutionContext.InvokeCommand.ExpandString($message)

InvokeCommand.ExpandString Geçerli yürütme bağlamında çağrısı, değiştirme için geçerli kapsamdaki değişkenleri kullanır. Burada önemli olan, değişkenlerin $message daha var olmadan çok erken tanımlanabilir olmasıdır.

Bunu biraz daha genişletirsek, bu değiştirme işlemini farklı değerlerle tekrar tekrar gerçekleştirebiliriz.

$message = 'Hello, $Name!'
$nameList = 'Mark Kraus','Kevin Marquette','Lee Dailey'
foreach($name in $nameList){
    $ExecutionContext.InvokeCommand.ExpandString($message)
}

Bu fikri devam ettirebilmek için; bunu yapmak için bir metin dosyasından büyük bir e-posta şablonunu içeri aktarıyor olabilirsiniz. Mark Kraus'a bu öneri için teşekkür etmek zorundayım.

Sizin için en uygun olan şey

Biçim dizesi yaklaşımının hayranıyım. Bunu kesinlikle daha karmaşık dizelerle veya birden çok değişken varsa yaparım. Kısa olan her şeyde bunlardan herhangi birini kullanabilirim.

Başka birşey var mı?

Bu konuda çok fazla yer kapladim. Umarım yeni bir şeyler öğrenerek çekip gidersiniz.

Dize ilişkilendirmeyi mümkün hale getiren yöntemler ve özellikler hakkında daha fazla bilgi edinmek isterseniz, başvuru belgeleri için aşağıdaki listeye bakın.