Niezawodny sposób na skrypt Bash, aby uzyskać pełną ścieżkę do siebie [duplikat]

to pytanie ma już odpowiedzi tutaj : Jak mogę pobrać katalog źródłowy skryptu Bash z samego skryptu? (68 odpowiedzi) Zamknięte 4 lata temu.

Mam skrypt Basha, który musi znać pełną ścieżkę. Staram się znaleźć ogólnie zgodny sposób, aby to zrobić, nie kończąc na względnych lub funky wyglądających ścieżek. Muszę tylko wspierać Basha, a nie sh, csh itp.

Co znalazłem do tej pory:

  1. Zaakceptowana odpowiedź na uzyskanie katalogu źródłowego skryptu Bash od wewnątrz adresy uzyskanie ścieżki skryptu przez dirname $0, co jest w porządku, ale może to zwrócić względną ścieżkę (jak .), co jest problemem, jeśli chcesz zmienić katalogi w skrypcie, a ścieżka nadal wskazuje na katalog skryptu. / Align = "left" /

  2. Zaakceptowana odpowiedź na bash script absolute path with OS X (OS X specyficzne, ale odpowiedź działa niezależnie) daje funkcję, która będzie testować, aby sprawdzić, czy $0 wygląda relatywnie, a jeśli tak, to pre-pend $PWD do niego. Ale wynik może nadal zawierać bity względne (chociaż ogólnie jest absolutny) - na przykład, jeśli skrypt znajduje się t w katalogu /usr/bin, a Ty jesteś w /usr i wpisujesz bin/../bin/t, aby go uruchomić (tak, to jest zawiłe), kończysz z /usr/bin/../bin jako ścieżką do katalogu skryptu. Które Działa , ale...

  3. Rozwiązanie readlink na tej stronie , które wygląda tak:

    # Absolute path to this script. /home/user/bin/foo.sh
    SCRIPT=$(readlink -f $0)
    # Absolute path this script is in. /home/user/bin
    SCRIPTPATH=`dirname $SCRIPT`
    

    Ale readlink nie jest POSIX i najwyraźniej rozwiązanie opiera się na GNU readlink, gdzie BSD nie będzie działać z jakiegoś powodu (nie mam dostępu do systemu podobnego do BSD do sprawdzenia).

Więc, różne sposoby robienia tego, ale wszystkie mają swoje zastrzeżenia.

Jaki byłby lepszy sposób? Gdzie "lepsze" oznacza:

  • daje mi absolutną ścieżkę.
  • usuwa funky bity, nawet gdy są wywoływane w zawiły sposób(patrz komentarz na #2 powyżej). (Np. przynajmniej umiarkowanie kanoniczne / align = "left" / )
  • opiera się tylko na bash-isms lub rzeczach, które są prawie pewne, że będą na najpopularniejszych systemach * nix (GNU / Linux, BSD i systemach podobnych do BSD, takich jak OS X, itp.).
  • unika wywoływania zewnętrznych programów, jeśli to możliwe(np. preferuje wbudowane Bash).
  • (Updated , thanks for the heads up, wich ) It doesn 't have to resolve symlinks (in fact, I' d kind of leave them alone, but that ' s not a requirement).
 760
Author: ribbons, 2011-01-23

23 answers

Oto co wymyśliłem (edit: plus kilka poprawek dostarczonych przez sfstewman, levigroker, Kyle Strand i Rob Kennedy ), to wydaje się w większości pasować do moich "lepszych" kryteriów:

SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"

Ta linia SCRIPTPATH wydaje się szczególnie okrężna, ale potrzebujemy jej raczej niż SCRIPTPATH=`pwd`, aby prawidłowo obsługiwać spacje i dowiązania symboliczne.

Włączenie przekierowania Wyjściowego (>/dev/null 2>&1) obsługuje rzadkie(?) przypadek, w którym cd może wytworzyć wyjście, które / align = "center" bgcolor = "# e0ffe0 " / cesarz Chin / / align = center / (Takie jak cd jest nadpisywany do ls katalogu po przełączeniu na niego.)

Zauważ również, że sytuacje Ezoteryczne, takie jak wykonywanie skryptu, który w ogóle nie pochodzi z pliku w dostępnym systemie plików (co jest całkowicie możliwe), nie są tam uwzględniane (ani w żadnej z innych odpowiedzi, które widziałem).

 658
Author: T.J. Crowder,
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
2020-01-29 15:10:19

Dziwię się, że nie wspomniano tu o komendzie realpath. Rozumiem, że jest szeroko przenośny / portowany.

Twoje początkowe rozwiązanie staje się:

SCRIPT=`realpath $0`
SCRIPTPATH=`dirname $SCRIPT`

I pozostawić dowiązania symboliczne nierozwiązane zgodnie z Twoimi preferencjami:

SCRIPT=`realpath -s $0`
SCRIPTPATH=`dirname $SCRIPT`
 265
Author: Darshan Rivka Whittle,
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
2012-06-20 07:11:49

Najprostszym sposobem, jaki znalazłem, aby uzyskać pełną ścieżkę kanoniczną w Bash jest użycie cd i pwd:

ABSOLUTE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"

Użycie ${BASH_SOURCE[0]} zamiast $0 powoduje takie samo zachowanie niezależnie od tego, czy skrypt jest wywoływany jako <name> czy source <name>.

 192
Author: Andrew Norrie,
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-31 14:11:31

Musiałem dzisiaj wrócić do tej kwestii i znalazłem Pobierz katalog źródłowy skryptu Bash z samego skryptu:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

W linked answer jest więcej wariantów, np. w przypadku, gdy sam skrypt jest dowiązaniem symbolicznym.

 59
Author: Felix Rabe,
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
2019-05-03 19:21:21

Użycie:

SCRIPT_PATH=$(dirname `which $0`)

which wypisuje na standardowe wyjście pełną ścieżkę pliku wykonywalnego, który zostałby wykonany, gdy przekazany argument został wprowadzony w wierszu polecenia powłoki (co zawiera $0)

dirname usuwa przyrostek nie-katalogowy z nazwy pliku.

W ten sposób otrzymujesz pełną ścieżkę skryptu, bez względu na to, czy ścieżka została określona, czy nie.

 42
Author: Matt,
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-31 21:55:54

Pobranie ścieżki bezwzględnej skryptu powłoki

Nie używa opcji -f w readlink, dlatego powinna działać na BSD/Mac OS X.

Podpory

  • źródło ./ script (wywołany przez . operator kropki)
  • absolutna Ścieżka / Ścieżka / do / skryptu
  • ścieżka względna jak ./ script
  • / path / dir1/../ dir2 / dir3/./ script
  • wywołane z dowiązania symbolicznego
  • gdy dowiązanie symboliczne jest zagnieżdżone np.) foo->dir1/dir2/bar bar->./../doe doe->script
  • gdy rozmówca zmienia nazwa skryptów

Szukam przypadków narożnych, w których ten kod nie działa . Proszę dać mi znać.

Kod

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
while([ -h "${SCRIPT_PATH}" ]); do
    cd "`dirname "${SCRIPT_PATH}"`"
    SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
done
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
SCRIPT_PATH="`pwd`";
popd  > /dev/null
echo "srcipt=[${SCRIPT_PATH}]"
echo "pwd   =[`pwd`]"

Znany issus

Skrypt musi być gdzieś na dysku . Niech to będzie przez sieć. jeśli spróbujesz uruchomić ten skrypt z rury to nie zadziała

wget -o /dev/null -O - http://host.domain/dir/script.sh |bash
Technicznie rzecz biorąc, jest niezdefiniowany. Praktycznie rzecz biorąc, nie ma rozsądnego sposobu, aby to wykryć. (Współpro-proces nie może uzyskać dostępu do środowiska rodzic.)
 40
Author: GreenFox,
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-31 21:51:50

Ponieważ realpath nie jest domyślnie instalowany na moim systemie Linux, działa dla mnie:

SCRIPT="$(readlink --canonicalize-existing "$0")"
SCRIPTPATH="$(dirname "$SCRIPT")"

$SCRIPT będzie zawierać prawdziwą ścieżkę do skryptu i $SCRIPTPATH prawdziwą ścieżkę do katalogu zawierającego skrypt.

Przed użyciem przeczytaj komentarze tej odpowiedzi .

 26
Author: ypid,
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-31 21:52:42

Łatwy do odczytania? Poniżej jest alternatywa. Ignoruje dowiązania symboliczne

#!/bin/bash
currentDir=$(
  cd $(dirname "$0")
  pwd
)

echo -n "current "
pwd
echo script $currentDir

Odkąd kilka lat temu opublikowałem powyższą odpowiedź, rozwinąłem swoją praktykę do używania tego specyficznego paradygmatu Linuksa, który poprawnie obsługuje dowiązania symboliczne:

ORIGIN=$(dirname $(readlink -f $0))
 19
Author: gerardw,
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
2019-03-05 23:10:51

Możesz spróbować zdefiniować następującą zmienną:

CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"

Lub możesz wypróbować następującą funkcję w Bash:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

Funkcja ta przyjmuje jeden argument. Jeśli argument ma już ścieżkę bezwzględną, wypisuje ją taką, jaką jest, w przeciwnym razie wypisuje zmienną $PWD + argument nazwy pliku (bez prefiksu ./).

Powiązane:

 13
Author: kenorb,
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
2019-06-23 21:16:11

Po Prostu:

BASEDIR=$(readlink -f $0 | xargs dirname)

Fantazyjne operatory nie są potrzebne.

 11
Author: poussma,
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-31 21:58:48

ODPOWIEDŹ na to pytanie bardzo późno, ale używam:

SCRIPT=$( readlink -m $( type -p $0 ))      # Full path to script
BASE_DIR=`dirname ${SCRIPT}`                # Directory script is run in
NAME=`basename ${SCRIPT}`                   # Actual name of script even if linked
 10
Author: Stormcloud,
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
2014-03-24 16:11:39

Umieściliśmy nasz własny produkt realpath-lib na Githubie do bezpłatnego i nieobciążonego użytku społeczności.

Bezwstydna wtyczka, ale z tą biblioteką Basha możesz:

get_realpath <absolute|relative|symlink|local file>

Ta funkcja jest rdzeniem biblioteki:

function get_realpath() {

if [[ -f "$1" ]]
then 
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then 
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else 
        # file *must* be local
        local tmppwd="$PWD"
    fi
else 
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

Nie wymaga żadnych zewnętrznych zależności, tylko Bash 4+. Zawiera również funkcje do get_dirname, get_filename, get_stemname and validate_path validate_realpath. Jest darmowy, czysty, prosty i dobrze udokumentowany, więc może być również używany do celów edukacyjnych i bez wątpienia można to poprawić. Spróbuj na różnych platformach.

Update: po pewnym przejrzeniu i przetestowaniu zastąpiliśmy powyższą funkcję czymś, co osiąga ten sam wynik (bez użycia dirname, tylko czysty Bash), ale z lepszą wydajnością:

function get_realpath() {

    [[ ! -f "$1" ]] && return 1 # failure : file does not exist.
    [[ -n "$no_symlinks" ]] && local pwdp='pwd -P' || local pwdp='pwd' # do symlinks.
    echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result.
    return 0 # success

}

Obejmuje to również ustawienie środowiska no_symlinks, które zapewnia możliwość rozwiązywania dowiązań symbolicznych do fizycznego systemu. Domyślnie zachowuje dowiązania symboliczne nienaruszone.

 8
Author: AsymLabs,
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
2013-10-05 13:15:16

Bourne shell (sh) sposób zgodny:

SCRIPT_HOME=`dirname $0 | while read a; do cd $a && pwd && break; done`
 4
Author: Haruo Kinoshita,
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-31 15:11:12

Rozważając ten problem ponownie: istnieje bardzo popularne rozwiązanie, które jest przywołane w tym wątku, który ma swoje pochodzenie TUTAJ :

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Trzymałem się z dala od tego rozwiązania ze względu na użycie dirname - może to powodować trudności międzyplatformowe, szczególnie jeśli skrypt musi być zablokowany ze względów bezpieczeństwa. Ale jako czystą alternatywę Basha, jak o użyciu:

DIR="$( cd "$( echo "${BASH_SOURCE[0]%/*}" )" && pwd )"

Czy to jest opcja?

 3
Author: AsymLabs,
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-05-23 12:10:48

Jeśli używamy Basha uważam, że jest to najwygodniejszy sposób, ponieważ nie wymaga wywołania żadnych zewnętrznych poleceń:

THIS_PATH="${BASH_SOURCE[0]}";
THIS_DIR=$(dirname $THIS_PATH)
 3
Author: Nordlöw,
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
2014-04-18 20:05:31

Przyjęte rozwiązanie ma niewygodne (dla mnie) nie być "zdolne do źródła":
jeśli zadzwonisz z "source ../../yourScript", $0 byłoby "bash"!

Następująca funkcja (dla bash >= 3.0) daje mi właściwą ścieżkę, jednak skrypt może być wywołany (bezpośrednio lub poprzez source, ze ścieżką bezwzględną lub względną):
(przez "właściwą ścieżkę" mam na myśli pełną ścieżkę bezwzględną wywołanego skryptu, nawet gdy wywołany jest z innej ścieżki, bezpośrednio lub z "source")

#!/bin/bash
echo $0 executed

function bashscriptpath() {
  local _sp=$1
  local ascript="$0"
  local asp="$(dirname $0)"
  #echo "b1 asp '$asp', b1 ascript '$ascript'"
  if [[ "$asp" == "." && "$ascript" != "bash" && "$ascript" != "./.bashrc" ]] ; then asp="${BASH_SOURCE[0]%/*}"
  elif [[ "$asp" == "." && "$ascript" == "./.bashrc" ]] ; then asp=$(pwd)
  else
    if [[ "$ascript" == "bash" ]] ; then
      ascript=${BASH_SOURCE[0]}
      asp="$(dirname $ascript)"
    fi  
    #echo "b2 asp '$asp', b2 ascript '$ascript'"
    if [[ "${ascript#/}" != "$ascript" ]]; then asp=$asp ;
    elif [[ "${ascript#../}" != "$ascript" ]]; then
      asp=$(pwd)
      while [[ "${ascript#../}" != "$ascript" ]]; do
        asp=${asp%/*}
        ascript=${ascript#../}
      done
    elif [[ "${ascript#*/}" != "$ascript" ]];  then
      if [[ "$asp" == "." ]] ; then asp=$(pwd) ; else asp="$(pwd)/${asp}"; fi
    fi  
  fi  
  eval $_sp="'$asp'"
}

bashscriptpath H
export H=${H}

Kluczem jest wykrycie przypadku" source" i użycie ${BASH_SOURCE[0]}, aby odzyskać rzeczywisty skrypt.

 2
Author: VonC,
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
2011-06-24 02:45:06

One liner

`dirname $(realpath $0)`
 2
Author: Abhijit,
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
2015-12-18 02:02:32

Być może przyjęta odpowiedź na poniższe pytanie może być pomocna.

Jak mogę sprawdzić zachowanie READLINK-F GNU na komputerze Mac?

Biorąc pod uwagę, że po prostu chcesz kanonikować nazwę, którą otrzymujesz od konkatenacji $PWD i $0 (zakładając, że $0 nie jest absolutna na początku), po prostu użyj serii zamienników regex wzdłuż linii abs_dir=${abs_dir//\/.\//\/} i takich.

Tak, Wiem, że wygląda okropnie, ale zadziała i jest czystym Bashem.

 2
Author: wich,
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
2020-08-27 12:57:46

Spróbuj tego:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))
 1
Author: diyism,
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
2014-08-29 03:05:05

Do diabła z tym zrobiłem trochę hakowania na skrypcie, który robi rzeczy czysto tekstowo, czysto w Bash. Mam nadzieję, że złapałem wszystkie przypadki edge ' a.

Zauważ, że ${var//pat/repl}, o którym wspomniałem w drugiej odpowiedzi, nie działa, ponieważ nie można go zastąpić tylko najkrótszym możliwym dopasowaniem, co jest problemem dla zastąpienia /foo/../, ponieważ np. /*/../ weźmie wszystko przed nim, a nie tylko pojedynczy wpis. A ponieważ te wzorce nie są tak naprawdę wyrażeniami regularnymi, nie widzę, jak można to zrobić praca. Oto ładnie zawiłe rozwiązanie, które wymyśliłem, baw się dobrze. ;)

Przy okazji, daj mi znać, jeśli znajdziesz jakieś nieobsługiwane sprawy.
#!/bin/bash

canonicalize_path() {
  local path="$1"
  OIFS="$IFS"
  IFS=$'/'
  read -a parts < <(echo "$path")
  IFS="$OIFS"

  local i=${#parts[@]}
  local j=0
  local back=0
  local -a rev_canon
  while (($i > 0)); do
    ((i--))
    case "${parts[$i]}" in
      ""|.) ;;
      ..) ((back++));;
      *) if (($back > 0)); then
           ((back--))
         else
           rev_canon[j]="${parts[$i]}"
           ((j++))
         fi;;
    esac
  done
  while (($j > 0)); do
    ((j--))
    echo -n "/${rev_canon[$j]}"
  done
  echo
}

canonicalize_path "/.././..////../foo/./bar//foo/bar/.././bar/../foo/bar/./../..//../foo///bar/"
 0
Author: wich,
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-31 21:48:12

Przez jakiś czas używałem z powodzeniem następującego podejścia (nie na OS X), i używa tylko wbudowanej powłoki i obsługuje 'source foobar.sh / align = "left" /

Jeden problem z poniższym (pośpiesznie złożonym) przykładowym kodem jest taki, że funkcja używa $PWD, która może, ale nie musi być poprawna w czasie wywołania funkcji. Więc trzeba się tym zająć.

#!/bin/bash

function canonical_path() {
  # Handle relative vs absolute path
  [ ${1:0:1} == '/' ] && x=$1 || x=$PWD/$1
  # Change to dirname of x
  cd ${x%/*}
  # Combine new pwd with basename of x
  echo $(pwd -P)/${x##*/}
  cd $OLDPWD
}

echo $(canonical_path "${BASH_SOURCE[0]}")

type [
type cd
type echo
type pwd
 0
Author: andro,
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-31 22:02:51

Yet another way to do this:

shopt -s extglob

selfpath=$0
selfdir=${selfpath%%+([!/])}

while [[ -L "$selfpath" ]];do
  selfpath=$(readlink "$selfpath")
  if [[ ! "$selfpath" =~ ^/ ]];then
    selfpath=${selfdir}${selfpath}
  fi
  selfdir=${selfpath%%+([!/])}
done

echo $selfpath $selfdir
 -1
Author: Meow,
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
2014-12-19 14:02:50

Prościej, to jest to, co działa dla mnie:

MY_DIR=`dirname $0`
source $MY_DIR/_inc_db.sh
 -4
Author: Elendurwen,
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
2016-11-15 11:31:48