здесь моя проблема.
Позвольте мне описать ситуацию: я работаю на большом количестве серверов, которые содержат большое количество клиентов; все они имеют веб-пространство, но только некоторые из них используют Wordpress.
По соображениям безопасности я хотел бы получить версию Wordpress всех установок Wordpress для определенного сервера (я бы применил этот процесс к другим после того, как нашел решение).
Я нашел файл /wp-includes/version.php, который содержит строку "$ wp_version = 'xxx" - кажется идеальным для того, чтобы следить за установками клиентов и уведомлять их, когда их версия опасна.
Я начал писать о командной строке, которую я бы затем помещал в cron для получения результатов один раз в месяц:
for files in $(find /home -type f -iwholename "*/wp-includes/version.php") ; do domain=$(echo $files | awk -F'domains/' '{print $2}' | awk -F'/' '{print $1}') ; version=$(grep "wp_version = " $files | awk -F'=' '{print $2}') ; echo "$domain : $version" ; done | grep -v "4.8" | sed -e "s/'/ /g" -e "s/;/ /g"
Вышеуказанная строка дает результат такого рода:
domain.com : 4.1.3
another.com : 4.7.6
again.com : 4.7.6
Похоже, я получил результат, который хотел, но, как вы можете видеть, эта командная строка ДЕЙСТВИТЕЛЬНО длинна, и даже если я пробовал разные версии, я не нашел элегантный вариант.
Конечно, я пробовал разные версии до этого результата, и это единственный, который работает правильно; и я не смог найти что-то подобное, но лучше. Реальная проблема, я думаю, связана с определениями переменных из результата; Я изучаю awk, но это что-то вроде уродливого, даже если это потрясающий инструмент. Команда sed в конце очищает исходный результат, который выглядит следующим образом:
domain.com : '4.1.3';
another.com : '4.7.6';
again.com : '4.7.6';
Wp-includes/version.php выглядит примерно так:
<?php
/**
* The WordPress version string
*
* @global string $wp_version
*/
$wp_version = '3.9'; # for example
...
Не могли бы вы рассказать мне, видите ли вы какую-либо "оптимизацию"? Это больше связано с образованием, чем с реальной проблемой.
Изменение: наиболее оптимизированная версия на данный момент является следующей, на мой взгляд (достаточно ясно для легкой модификации, чистого результата, а не так трудно понять функции):
for f in $(find /home -iwholename "*/wp-includes/version.php") ; do d=$(echo $f | awk -F'domains/' '{print $2}' | cut -d"/" -f1) ; v=$(grep '$wp_version = ' $f | sed -e 's/$wp_version = //g' -e "s/'//g" -e 's/;//g') ; echo "$v - $d" ; done
Я не знаю, что вы намерены более элегантным, что является довольно субъективным критерием, но вот несколько советов о более эффективном использовании некоторых команд:
find
более мощное, чем то, что вы используете. Он может выполнять поиск с использованием регулярных выражений (-regex
), выполнять команды в найденных файлах (действие -exec
)... Примеры:
$ re1=".*/domains/[^/]*"
$ find /home -type d -regex "$re1" -printf "%f : \n"
domain.com :
another.com :
again.com :
$ re2="*/domains/*/wp-includes/version.php"
$ re3="wp_version"
$ find /home -type f -ipath "$re2" -exec grep "$re3" '{}' \;
$wp_version = '1.1'; # for example
$wp_version = '2.2'; # for example
$wp_version = '3.3'; # for example
Параметр {}
-exec
заменяет путь найденного файла. Обратите внимание, что команды -exec
должны быть -exec
которая должна быть экранирована (\;
), чтобы предотвратить ее интерпретацию оболочкой. find
также может комбинировать несколько сгруппированных (\(...\)
) тестовых выражений -o
(-o
, -a
):
$ find /home \( -type d -regex "$re1" -printf "%f : " \) -o \
\( -type f -ipath "$re2" -exec grep "wp_version" '{}' \; \)
domain.com : $wp_version = '1.1'; # for example
another.com : $wp_version = '2.2'; # for example
again.com : $wp_version = '3.3'; # for example
grep
тоже, если это недавняя версия GNU grep
, более мощна, чем вы используете. Он имеет частичную поддержку регулярных выражений perl
(опция -P
) и может выводить только соответствующую часть (-o
). Пример:
$ re3="\\\$wp_version\s*=\s*'\K\d+(\.\d+)*"
$ grep -Po "$re3" version.php
1.1
Если мы склеиваем все это вместе и используем переменные bash для лучшей читаемости (печально известный чит, чтобы сократить конечную командную строку), мы можем использовать следующее:
$ re1=".*/domains/[^/]*"
$ re2="*/domains/*/wp-includes/version.php"
$ re3="\\\$wp_version\s*=\s*'\K\d+(\.\d+)*"
$ find /home \( -type d -regex "$re1" -printf "%f : " \) -o \
\( -type f -ipath "$re2" -exec grep -Po "$re3" '{}' \; \)
domain.com : 1.1
another.com : 2.2
again.com : 3.3
Но все это очень сложно. Более того, он работает только в том случае, если для домена есть один и только один файл версии, и он не отфильтровывает версии более поздними, чем 4.8
. Цикл и немного черной магии bash, вероятно, намного проще, легче понять и поддерживать, и легко расширить с помощью фильтрации версий:
re1="*/domains/*/wp-includes/version.php"
re2="\\\$wp_version\s*=\s*'\K\d+(\.\d+)*"
while read -d $'\0' f; do
[[ $f =~ .*/domains/([^/]+)/.* ]] && domain="${BASH_REMATCH[1]}"
version=$( grep -Po "$re2" "$f" )
[[ ! $version =~ 4\.8(\.\d+)* ]] && printf "%s : %s\n" "$domain" "$version"
done < <( find . -type f -ipath "$re1" -print0 )
Обратите внимание на использование разделителя \0
(вместо новых строк) в read
(-d $'\0'
) и find
-Print0
). Это может помочь, если у вас есть странные имена каталогов.
version=$( awk -F"[\"']" '/^\$wp_version/{print $2}' "$files" )
Получить версию
$ cat version.php
<?php
/**
* The WordPress version string
*
* @global string $wp_version
*/
$wp_version = '3.9'; # for example
...
# used field separator either single quote or double quote
$ awk -F"[\"']" '/^\$wp_version/{print $2}' version.php
3.9
Для домена вы можете изменить
domain=$(echo $files | awk -F'domains/' '{print $2}' | awk -F'/' '{print $1}') ;
к
domain=$(awk -F'domains/' '{split($2,tmp,/\//); print tmp[1]}' <<<"$files")
Предположим, если у вас есть что-то вроде
$ files="path/to/domains/domain.com/wordpress/wp-includes/version.php"
$ awk -F'domains/' '{split($2,tmp,/\//); print tmp[1]}' <<<"$files"
domain.com
domain=$(awk -F'domains/' '{split($2,tmp,/\//); print tmp[1]}' <<<"$files")
Вы можете значительно упростить свою логику и сделать ее более эффективной и читаемой:
config_re='/wp_includes/version.php$'
while IFS=: read -r file match; do
[[ $file =~ $config_re ]] || continue # skip if it is some other version.php
# logic to extract the domain from file variable
IFS=/ read -ra domain_arr <<< "$file"
domain="${domain[2]}" # adjust the array index as needed
# logic to extract version from matched part
IFS='=' read -ra version_arr <<< "$match"
version="${version_arr[1]}"
done < <(find /path/to/domains -type f -name version.php -exec grep '$wp_version' {} /dev/null \;)
find/path/to/domains -type f -name version.php -exec grep -H '$wp_version' {} \;
извлекает все матчи за один снимок; grep -H
гарантирует, что полный путь к файлу версии (обратите внимание, что полный путь в аргументе find
directory имеет префикс в соответствие на выходеЯ не тестировал этот код. Я готов исправить это, если вы столкнетесь с какими-либо проблемами.
find
создает разделенный запятыми вывод (/ path / to / domain / file: $ wp_version ...) и цикл чтения считывает их в file
двух переменных и match
с IFS, установленным в :
который является входным разделителем. Внутри цикла мы извлекаем домен из полного пути к файлу и версию из совпадения. Это все.