Zadanie jest proste: mamy skrypt z poleceniami SQL, który chcemy wywołać przez sqlcmd
. Ale – w skrypcie wykorzystujemy zmienną, która na dodatek zawiera ścieżkę do katalogu. Jako przykład niech posłuży taki fragment zapisany w pliku SELECT.sql
:
SELECT Imie = 'Bartek', Zmienna = '$(ScriptPath)'
Wywołanie z poziomu cmd
nie stwarza problemów:
C:\> cd tmp C:\tmp> sqlcmd -r1 -v ScriptPath="C:\tmp" -i SELECT.sql -S Serwer-f 1250 Bartek Zmienna ------ ------- Bartek C:\tmp
Poszczególne przełączniki oznaczają:
-r1
– chcę zobaczyć błędy na ekranie-v
– przekazuję zmienną o nazwie ScriptPath z wartością zawierającą jakąś ścieżkę-i
– nazwa skryptu wejściowego-S
– mój serwer-f
– strona kodowa
I super, a jeśli potrzebujemy uruchomić w PowerShell?
PS C:\tmp> sqlcmd -r1 -v ScriptPath="C:\tmp" -i SELECT.sql -S Serwer -f 1250 Sqlcmd: ':\tmp': Invalid argument. Enter '-?' for help.PS C:\tmp>
Czemu tak?
Powodem nie jest ścieżka, tylko sam dwukropek, który jest dla PowerShell znakiem specjalnym. Problem w tym, że w tym przypadku nie daje się to ładnie obejść (np. przez znak `) i trzeba kombinować. Znalazłem dwa rozwiązania tego problemu. Pierwsze – zadeklarować zmienną jako tablicę i użyć ją w poleceniu, drugie – zastosować tablicę od razu w poleceniu i zrobić wszystko w ramach jednej linijki:
PS C:\tmp> $cmdparams = @('ScriptPath="C:\tmp"') PS C:\tmp> $cmdparams ScriptPath="C:\tmp" PS C:\tmp> sqlcmd -r1 -v $cmdparams -i SELECT.sql -S Serwer -f 1250 Bartek Zmienna ------ ------- Bartek C:\tmp PS C:\tmp> sqlcmd -r1 -v @('ScriptPath="C:\tmp"') -i SELECT.sql -S Serwer -f 1250 Bartek Zmienna ------ ------- Bartek C:\tmp
Wszystko fajnie, ale mamy podaną ścieżkę wprost. A co jeśli chcemy podać ścieżkę dynamicznie? W tym przypadku też zrobię w jednej linijce, a wynik przekażę do pętli ForEach-Object
, w której wykorzystam zmienną $_
. Dlaczego do pętli? Bo w przeciwnym przypadku będzie błąd Expressions are only allowed as the first element of a pipeline.
PS C:\tmp> 'ScriptPath="' + (Get-Item -Path '.\' -Verbose).FullName +'"' | ForEach-Object {sqlcmd -r1 -v @($_) -i SELECT.sql -S Serwer -f 1250} Imie Zmienna ------ ------- Bartek C:\tmp
Albo krócej, stosując znak %
jako alias dla ForEach-Object
:
PS C:\tmp> 'ScriptPath="' + (Get-Item -Path '.\' -Verbose).FullName +'"' | % {sqlcmd -r1 -v @($_) -i SELECT.sql -S Serwer -f 1250} Imie Zmienna ------ ------- Bartek C:\tmp
Aktualizacja 2015.10.20 Można też zastosować formatowanie za pomocą parametru -f
(podpowiedziane przez Maćka J.):
PS C:\tmp> sqlcmd -S Serwer -r1 -v ScriptPath=("""{0}""" -f (Get-Item -Path '.\' -Verbose).FullName) -i SELECT.sql -f 1250