Unikanie podwójnych cudzysłowów w skrypcie wsadowym
Jak mógłbym zastąpić wszystkie podwójne cudzysłowy w parametrach pliku wsadowego podwójnymi cudzysłowami? Jest to mój bieżący plik wsadowy, który rozszerza wszystkie parametry wiersza poleceń wewnątrz łańcucha:
@echo off
call bash --verbose -c "g++-linux-4.1 %*"
Następnie używa tego ciągu do wywołania bash Cygwina, wykonując linuksowy kompilator krzyżowy. Niestety, dostaję parametry takie jak te przekazywane do mojego pliku wsadowego:
"launch-linux-g++.bat" -ftemplate-depth-128 -O3 -finline-functions
-Wno-inline -Wall -DNDEBUG -c
-o "C:\Users\Me\Documents\Testing\SparseLib\bin\Win32\LinuxRelease\hello.o"
"c:\Users\Me\Documents\Testing\SparseLib\SparseLib\hello.cpp"
Gdzie pierwszy cytat wokół pierwszej przekazanej ścieżki jest przedwcześnie zakończenie łańcucha przekazywanego do GCC i przekazanie reszty parametrów bezpośrednio do bash (co nie udaje się spektakularnie.)
Wyobrażam sobie, że jeśli Mogę połączyć parametry w pojedynczy ciąg znaków, a następnie uciec cudzysłowów powinno działać dobrze, ale mam trudności z określeniem, jak to zrobić. Czy ktoś wie?
4 answers
Znakiem escape w skryptach wsadowych jest ^
. Ale dla ciągów podwójnie cytowanych, podwojenie cudzysłowów:
"string with an embedded "" character"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-18 17:31:53
Odpowiedź Eplawlessa w prosty i efektywny sposób rozwiązuje jego specyficzny problem: zastępuje wszystkie "
instancje z całej listy argumentów \"
, co jest sposobem, w jaki Bash wymaga reprezentowania podwójnych cudzysłowów wewnątrz podwójnego cytowanego ciągu.
Aby ogólnie odpowiedzieć na pytanie jak uniknąć podwójnego cudzysłowu wewnątrz podwójnego cytowanego ciągu za pomocą cmd.exe
, interpreter wiersza poleceń systemu Windows (czy to w wierszu poleceń-często błędnie nazywany "Dos prompt" - lub w pliku wsadowym): Zobacz na dole PowerShell .
Tl; dr :
-
Ty musi używać
""
gdy przekazujemy łańcuch do pliku wsadowego (nother) a Ty może używać""
z aplikacjami utworzonymi za pomocą kompilatorów Microsoft C/C++/. Net (które również accept\"
), Które W Windows obejmują Pythona i węzeł.js :Przykład:
foo.bat "We had 3"" of rain."
-
Poniższe zasady dotyczą tylko plików wsadowych:
""
jest jedynym sposobem na uzyskanie interpretera poleceń (cmd.exe
), aby traktował cały cytowany łańcuch jako argument jako pojedynczy argument.Niestety, nie tylko zamykające się podwójne cudzysłowy są zachowane (jak zwykle), ale także podwojone znaki ucieczki, więc uzyskanie zamierzonego ciągu jest dwustopniowe proces; np. zakładając, że dwukrotnie cytowany łańcuch jest przekazywany jako pierwszy argument,
%1
:set "str=%~1"
usuwa podwójne cudzysłowy;set "str=%str:""="%"
następnie konwertuje podwójne cudzysłowy na pojedyncze.
Pamiętaj, aby używać podwójnych cudzysłowów wokół części przypisania, aby zapobiec niepożądanej interpretacji wartości.
-
\"
jest wymagane - jako jedyna opcja - przez wiele innych programy, (np. Ruby, Perl, a nawet własny PowerShell Microsoftu (!)nie jest to jednak możliwe, ponieważ nie jest to możliwe.]}-
\"
jest tym, co wiele programów wykonywalnych i interpreterów wymaga - włączając w to własny PowerShell Microsoftu po przekazaniu ciągów z zewnątrz - lub, w przypadku Kompilatory Microsoftu, wspierają jako alternatywę dla""
- ostatecznie jednak, to do programu docelowego należy przeanalizowanie argumentu lista. - przykład:
foo.exe "We had 3\" of rain."
-
Jednak użycie
\"
może skutkować niechcianym, arbitralnym wykonywaniem poleceń i / lub przekierowaniem wejścia/wyjścia.]}:- następujące znaki przedstawiają to ryzyko:
& | < >
- na przykład, następujące wyniki w niezamierzonym wykonaniu
ver
polecenia; zobacz poniżej wyjaśnienie i następny punkt dla obejście:foo.exe "3\" of snow" "& ver."
- następujące znaki przedstawiają to ryzyko:
- tylko dla PowerShell tylko dla Windows ,
\""
jest solidną alternatywą.
-
-
Jeśli musisz użyć
\"
, są tylko 3 bezpieczne podejścia , które są jednak dość uciążliwe: końcówka kapelusza do T S za jego pomoc.-
Za pomocą (ewentualnie selektywne ) opóźnione rozszerzenie zmiennej w pliku wsadowym możesz przechowywać literał
\"
W Zmiennej i odwoływać się do tej zmiennej wewnątrz ciągu"..."
używając składni!var!
- zobacz pomocną odpowiedź T S .- powyższe podejście, mimo że jest uciążliwe, ma tę zaletę, że można je zastosować metodycznie i że działa solidnie, z dowolnym wejście.
Tylko z ciągami LITERALNYMI-nie zawierającymi zmiennych - otrzymujesz podobnie metodyczne podejście: kategorycznie
^
- escape wszystkiecmd.exe
metacharaktery:" & | < >
i-jeśli chcesz również tłumić Rozszerzanie zmiennych-%
:foo.exe ^"3\^" of snow^" ^"^& ver.^"
-
W przeciwnym razie musisz sformułować swój łańcuch na podstawie rozpoznania, które części łańcucha
cmd.exe
uważa za nienotowane ze względu na błędna interpretacja\"
jako ograniczniki zamykające:W literalne części zawierające metacharaktery powłoki:
^
- escape them; używając powyższego przykładu, to&
musi być^
-Escape:foo.exe "3\" of snow" "^& ver."
W części z
%...%
-style odwołania do zmiennej : upewnij się, żecmd.exe
uważa je za część"..."
string i że wartości zmiennej same w sobie nie mają wbudowanego, niezrównoważonego cytaty - co nie zawsze jest możliwe .
-
Aby uzyskać podstawowe informacje, Czytaj dalej.
Tło
uwaga: jest to oparte na moich własnych eksperymentach. Daj mi znać, jeśli się mylę.
Powłoki podobne do POSIX, takie jak Bash w systemach uniksopodobnych, tokenizują listę argumentów (string) przed przekazaniem argumentów indywidualnie do programu docelowego. podziel listę argumentów na poszczególne słowa (dzielenie słów) i usuń znaki cytowania z wynikowych słów (usuwanie cytatów). To, co program docelowy podaje, jest koncepcyjnie tablicą pojedynczych argumentów z usuniętymi cudzysłowami (wymaganymi w składni).
Natomiast interpreter poleceń Windows najwyraźniej nie tokenizuje listy argumentów i po prostu przekazuje pojedynczy ciąg zawierający wszystkie argumenty - w tym znaki cytowania. - do program docelowy.
Jednak pewne wstępne przetwarzanie odbywa się przed przekazaniem pojedynczego ciągu znaków do programu docelowego: ^
znaki ucieczki. poza podwójnymi cytowanymi łańcuchami są usuwane (wydostają się z następującego znaku.), a odwołania do zmiennych (np. %USERNAME%
) są interpolowane jako pierwsze.
Tak więc, w przeciwieństwie do Uniksa, zadaniem programu docelowego jest analiza ciągu argumentów i rozbicie go na poszczególne argumenty za pomocą cudzysłowów usunięte. Tak więc, różne programy mogą hipotetycznie wymagać różnych metod ucieczki i nie ma jednego mechanizmu ucieczki, który jest gwarantowany do pracy ze wszystkimi programami - https://stackoverflow.com/a/4094897/45375 zawiera doskonałe tło anarchii, jaką jest parsowanie wiersza poleceń systemu Windows.
W praktyce, \"
jest bardzo powszechne, ale nie Bezpieczne , jak wspomniano powyżej:
Od cmd.exe
nie rozpoznaje \"
jako uciekającego podwójnego cudzysłowu, może błędnie interpretować późniejsze tokeny w linii poleceń jako nie cytowane i potencjalnie interpretować je jako polecenia i/lub przekierowania wejścia/wyjścia.
w skrócie: problem pojawia się, jeśli któraś z poniższych znaków podąża za otwierającym lub niezbalansowanym \"
: & | < >
; na przykład:
foo.exe "3\" of snow" "& ver."
cmd.exe
widzi następujące tokeny, wynikające z błędna interpretacja \"
jako zwykłego podwójnego cytatu:
"3\"
of
snow" "
- reszta:
& ver.
Ponieważ cmd.exe
uważa, że & ver.
jest niekanonicznym , interpretuje go jako &
(operator sekwencjonujący polecenia), po którym następuje nazwa polecenia do wykonania (ver.
- .
jest ignorowany; ver
przekazuje informacje o wersji cmd.exe
).
Ogólny efekt to:
- pierwszy,
foo.exe
jest wywoływany z pierwszy 3 tylko żetony. - następnie wykonywane jest polecenie
ver
.
Nawet jeśli przypadkowe polecenie nie zaszkodzi, Twoje ogólne polecenie nie będzie działać tak, jak zostało zaprojektowane, biorąc pod uwagę, że nie wszystkie argumenty są do niego przekazywane.
Wiele kompilatorów / interpreterów rozpoznaje tylko \"
- na przykład kompilator GNU C/C++, Python, Perl, Ruby, a nawet własny PowerShell Microsoftu wywołany z cmd.exe
- i, z wyjątkiem PowerShell z \""
, dla nich Nie ma prostego rozwiązania tego problemu.
Zasadniczo, musisz wiedzieć z góry, które fragmenty Twojej linii poleceń są błędnie interpretowane jako nienotowane i selektywnie ^
-unikaj wszystkich instancji & | < >
w tych fragmentach.
Dla kontrastu, użycie ""
jest bezpieczne, ale jest niestety obsługiwane tylko przez pliki wykonywalne oparte na kompilatorze Microsoft i pliki wsadowe (W przypadku plików wsadowych, z dziwactwami omówionymi powyżej).
By contrast, PowerShell, podczas wywoływania z zewnątrz - np. z cmd.exe
, czy to z linii poleceń, czy z pliku wsadowego - rozpoznaje tylko \"
a w Windows tym bardziej wytrzymałe \""
, pomimo tego, że wewnętrznie PowerShell używa `
jako znaku escape w dwu cytowanych łańcuchach, a także akceptuje ""
; np.:
powershell -c " \"ab c\".length"
działa (wyjścia4
), podobnie jak więcej solidnapowershell -c " \""ab c\"".length"
,Ale
powershell -c " ""ab c"".length"
breaks .
Informacje pokrewne
-
^
może być używany tylko jako znak escape w unquoted strings - wewnątrz dwucyfrowych łańcuchów^
nie jest specjalny i traktowany jako literalny.-
zastrzeżenie: użycie
^
w parametrach przekazywanych do instrukcjicall
jest złamane (dotyczy to zarówno użyciecall
: wywołanie innego pliku wsadowego lub binarnego i wywołanie podprogramu w tym samym pliku wsadowym):-
^
instancje w Double-quoted wartości są niewytłumaczalnie podwojone, zmiana przekazywanej wartości: na przykład, jeśli zmienna%v%
zawiera wartość literałowąa^b
,call :foo "%v%"
"a^^b"
(!) do%1
(pierwszy parametr) w podprogramie:foo
. -
użycie
^
Zcall
jest złamane w sumie w tym^
nie może być już używany do ucieczki znaków specjalnych : np.call foo.cmd a^&b
po cichu łamie (zamiast przekazywać dosłownea&b
zbytfoo.cmd
, jak to by było bezcall
) -foo.cmd
nie jest nawet wywoływany (!), przynajmniej na Windows 7.
-
-
zastrzeżenie: użycie
-
Nie jest to jednak żaden inny przypadek, który może być użyty do określenia, czy dany ciąg znaków jest podany w Komendzie . linia vs. wewnątrz pliku wsadowego; zobacz https://stackoverflow.com/a/31420292/45375
- Skrót: wewnątrz pliku wsadowego użyj
%%
. W wierszu poleceń,%
nie może być przechowywany, ale jeśli umieścisz^
na początku, końcu lub w nazwie zmiennej w łańcuchu nienotowanym (np.echo %^foo%
), możesz zapobiec ekspansji zmiennej (interpolacji); instancje%
w wierszu poleceń, które nie są częścią odniesienia do zmiennej, są traktowane jako literały (np.100%
).
- Skrót: wewnątrz pliku wsadowego użyj
-
Ogólnie rzecz biorąc, aby bezpiecznie pracować z wartościami zmiennych, które mogą zawierać spacje i znaki specjalne :
-
przypisanie: Załącz zarówno nazwę zmiennej, jak i wartość w pojedynczej parze podwójnych cudzysłowów ; np.
set "v=a & b"
przypisuje wartość literałowąa & b
do zmiennej%v%
(dla kontrastuset v="a & b"
uczyniłoby podwójną cudzysłowem część wartości). Ucieczka literalne instancje%
jako%%
(działa tylko w plikach wsadowych-patrz wyżej). -
: aby upewnić się, że ich wartość nie jest interpolowana, np.
echo "%v%"
nie poddaje wartości%v%
interpolacji i drukuje"a & b"
(należy jednak pamiętać, że podwójne cudzysłowy są również zawsze drukowane). Natomiastecho %v%
przekazuje literała
doecho
, interpretuje {[39] } jako operator sekwencjonujący polecenia i dlatego próbuje wykonaj polecenie o nazwieb
.
Zwróć również uwagę na powyższe zastrzeżenie ponownego użycia^
Zcall
. -
zewnętrzne programy zazwyczaj zajmują się usuwaniem zamykających się podwójnych cudzysłowów wokół parametrów, ale, jak zauważono, w plikach wsadowych musisz to zrobić sam (np. {[125] } aby usunąć zamykające się podwójne cudzysłowy z pierwszego parametru) i niestety, {159]} nie ma bezpośredniego sposobu, o którym wiem, aby uzyskać {120]} wiernie wydrukować wartość zmiennej bez dołączając podwójne cudzysłowy .
-
Neil oferuje obejście oparte na
for
, które działa tak długo, jak wartość nie ma osadzonych podwójnych cudzysłowów; np.:set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
-
Neil oferuje obejście oparte na
-
przypisanie: Załącz zarówno nazwę zmiennej, jak i wartość w pojedynczej parze podwójnych cudzysłowów ; np.
-
cmd.exe
czy nie rozpoznaje pojedyncze -cudzysłowy jako ograniczniki łańcuchów-są one traktowane jako literały i nie mogą być ogólnie używane do oddzielania łańcuchów z osadzonymi białymi spacjami; wynika również, że tokeny znajdujące się obok pojedynczych cytatów i wszystkie tokeny pomiędzy są traktowane jako nienotowane przezcmd.exe
i odpowiednio interpretowane.- jednakże, biorąc pod uwagę, że programy docelowe ostatecznie wykonują własne parsowanie argumentów, niektóre programy, takie jak Ruby, rozpoznają pojedyncze cytowane ciągi nawet w systemie Windows; natomiast pliki wykonywalne C / C++, Perl i Python rozpoznają je , a nie.
Nawet jeśli program docelowy jest obsługiwany, nie jest jednak wskazane używanie single-quoted ciągi, ponieważ ich zawartość nie jest chroniona przed potencjalnie niechcianą interpretacją przezcmd.exe
.
- jednakże, biorąc pod uwagę, że programy docelowe ostatecznie wykonują własne parsowanie argumentów, niektóre programy, takie jak Ruby, rozpoznają pojedyncze cytowane ciągi nawet w systemie Windows; natomiast pliki wykonywalne C / C++, Perl i Python rozpoznają je , a nie.
PowerShell
Windows PowerShell jest znacznie bardziej zaawansowaną powłoką niż cmd.exe
i jest częścią systemu Windows od wielu lat (i {593]} PowerShell Core przyniósł doświadczenie PowerShell do macOS i Linux, jak również).
PowerShell działa konsekwentnie wewnętrznie w odniesieniu do cytat:
- wewnątrz cudzysłowów, użyj
`"
lub""
, aby uciec od cudzysłowów - wewnątrz cudzysłowów, użyj
''
, aby uciec od cudzysłowów
Działa to na linii poleceń PowerShell i podczas przekazywania parametrów do skryptów lub funkcji PowerShell z wewnątrz PowerShell.
W przypadku, gdy nie jest to możliwe, nie jest to możliwe, ponieważ nie jest to możliwe, ponieważ nie jest to możliwe.,\""
- nic innego nie działa).
Niestety, wywołując zewnętrzne programy , stajesz przed koniecznością dostosowania zarówno własnych reguł cytowania PowerShella , jak i do ucieczki dla docelowego programu :
to problematyczne zachowanie jest również omówione i podsumowane w ten problem z GitHub docs
Podwójne - cytaty wewnątrz podwójne - cytaty ciągi :
PowerShell-wewnętrznie tłumaczy się na literalne3" of rain
.
Jeśli chcesz przekazać ten łańcuch do zewnętrznego programu, musisz zastosować program docelowy 's escaping dodatkowo do PowerShell' S ; powiedzmy, że chcesz przekazać łańcuch do programu C, który oczekuje osadzonych podwójnych cudzysłowów jako \"
:
foo.exe "3\`" of rain"
Zauważ jak zarówno `"
- aby PowerShell był szczęśliwy - i \
- aby program docelowy był szczęśliwy-musi być obecny.
Ta sama logika dotyczy wywołania pliku wsadowego, gdzie ""
musi być użyte:
foo.bat "3`"`" of rain"
Dla kontrastu, osadzanie pojedynczy - cudzysłów w podwójny -cytowany ciąg nie wymaga w ogóle ucieczki.
pojedyncze - cytaty wewnątrz pojedyncze - cytowane ciągi do nie wymagają extra ; rozważmy '2'' of snow'
, która jest reprezentacją PowerShella 2' of snow
.
foo.exe '2'' of snow'
foo.bat '2'' of snow'
PowerShell tłumaczy pojedyncze cytowane łańcuchy na podwójne cytowane przed przekazaniem ich do programu docelowego.
Jednakże, podwójne - cudzysłowy wewnątrz pojedyncze - cytowane ciągi , które nie wymagają ucieczki dla PowerShell , nadal muszą być zabezpieczone dla } programu docelowego:
foo.exe '3\" of rain'
foo.bat '3"" of rain'
PowerShell v3 wprowadził Magia --%
opcja , zwana symbolem stop-parsing , która łagodzi ból, przekazując cokolwiek po nim nieinterpretowane do programu docelowego, z wyjątkiem odniesień do zmiennych środowiskowych w stylu cmd.exe
(np. %USERNAME%
), które są rozszerzone; np.:
foo.exe --% "3\" of rain" -u %USERNAME%
Zauważ, że unikanie wbudowanego "
jako \"
tylko dla programu docelowego (a nie także dla PowerShell jako \`"
) jest wystarczające.
Jednak to podejście:
- nie pozwala na ucieczkę
%
znaków w celu uniknięcia rozszerzenia o zmienne środowisko. - wyklucza bezpośrednie użycie zmiennych i wyrażeń PowerShell; zamiast tego wiersz poleceń musi być zbudowany w zmiennej łańcuchowej w pierwszym kroku, a następnie wywołany z
Invoke-Expression
w sekundę.
Tak więc, pomimo wielu udoskonaleń, PowerShell nie ułatwił ucieczki podczas wywoływania zewnętrznych programów. Wprowadzono jednak obsługę pojedynczych cytowanych ciągów.
Zastanawiam się, czy jest to zasadniczo możliwe w świecie Windows, aby kiedykolwiek przełączyć się na model Unix pozwalając powłoka zrobić wszystkie tokenizacji i usuwania cytatów przewidywalnie, z przodu, program docelowy, a następnie wywołać program docelowy, przekazując wynikowe tokeny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-02 02:21:13
Google w końcu wymyślił odpowiedź. Składnia zastępowania łańcuchów w partii jest następująca:
set v_myvar=replace me
set v_myvar=%v_myvar:ace=icate%
Który produkuje "Replikuj mnie". Mój skrypt wygląda teraz tak:
@echo off
set v_params=%*
set v_params=%v_params:"=\"%
call bash -c "g++-linux-4.1 %v_params%"
, który zastępuje wszystkie instancje "
na \"
, odpowiednio zabezpieczone dla Basha.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-18 17:48:17
Jako dodatek do doskonała odpowiedź mklement0:
Prawie wszystkie pliki wykonywalne akceptują {[5] } jako ucieczkę "
. Bezpieczne użycie w cmd jest jednak prawie możliwe tylko przy użyciu DELAYEDEXPANSION.
Aby w jasny sposób wysłać literał "
do jakiegoś procesu, Przypisz \"
do zmiennej środowiskowej, a następnie użyj tej zmiennej, gdy chcesz przekazać cytat. Przykład:
SETLOCAL ENABLEDELAYEDEXPANSION
set q=\"
child "malicious argument!q!&whoami"
Uwaga SETLOCAL ENABLEDELAYEDEXPANSION
wydaje się działać tylko w plikach wsadowych. Aby uzyskać opóźnienie w interaktywnym sesja, start cmd /V:ON
.
Jeśli plik Batch nie działa z DELAYEDEXPANSION, możesz go tymczasowo włączyć:
::region without DELAYEDEXPANSION
SETLOCAL ENABLEDELAYEDEXPANSION
::region with DELAYEDEXPANSION
set q=\"
echoarg.exe "ab !q! & echo danger"
ENDLOCAL
::region without DELAYEDEXPANSION
Jeśli chcesz przekazać dynamiczną zawartość ze zmiennej, która zawiera cudzysłowy, które są unikalne jako ""
, możesz zastąpić ""
\"
przy rozbudowie:
SETLOCAL ENABLEDELAYEDEXPANSION
foo.exe "danger & bar=region with !dynamic_content:""=\"! & danger"
ENDLOCAL
Ten zamiennik nie jest bezpieczny z %...%
rozszerzeniem stylu!
W Przypadku OP bash -c "g++-linux-4.1 !v_params:"=\"!"
to bezpieczna wersja.
Jeśli z jakiegoś powodu nawet chwilowe włączenie DELAYEDEXPANSION nie jest opcją, Czytaj dalej:
Używanie \"
z cmd jest trochę bezpieczniejsze, jeśli zawsze trzeba unikać znaków specjalnych, a nie tylko czasami. (Mniej prawdopodobne jest, że zapomni o karetce, jeśli jest spójna...)
Aby to osiągnąć, należy poprzedzić dowolny cytat za pomocą caret (^"
), cytaty, które powinny dotrzeć do procesu potomnego, ponieważ literały muszą być dodatkowo unikane za pomocą backlash (\^"
). wszystkie meta znaki powłoki muszą być również z ^
, np. &
=> ^&
; |
=> ^|
; >
=> ^>
; itd.
Przykład:
child ^"malicious argument\^"^&whoami^"
Źródło: każdy cytuje argumenty linii poleceń w niewłaściwy sposób , zobacz "lepsza metoda cytowania"
Aby przekazać dynamiczną zawartość, należy upewnić się, że:
Część polecenia, która zawiera zmienną, musi być uznana za" cytowaną " przez cmd.exe
(jest to niemożliwe, jeśli zmienna może zawierać cudzysłowy - nie pisz %var:""=\"%
). Aby to osiągnąć, ostatnia "
przed zmienną i pierwsza "
po zmiennej nie są ^
-unikalne. cmd-metacharaktery pomiędzy tymi dwoma "
nie mogą być uciekane. Przykład:
foo.exe ^"danger ^& bar=\"region with %dynamic_content% & danger\"^"
To nie jest bezpieczne, jeśli {[32] } może zawierać niezrównane cudzysłowy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-01 20:35:47