“for”循环

时间:2017-10-27 02:55:37

标签: wordpress bash awk sed

这是我的麻烦。

让我来描述一下情况:我在大量服务器上工作,这些服务器包含大量客户;所有这些都有一个网站空间,但只有部分人使用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

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

您可以大大简化逻辑并使其更加高效和可读:

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目录参数中的完整路径以输出中的匹配为前缀

我还没有测试过这段代码。如果您遇到任何问题,我愿意修复它。

答案 2 :(得分:0)

我不知道你想要什么更优雅,这是一个相当主观的标准,但这里有一些关于更有效地使用某些命令的提示:

  1. ~/比您使用的功能更强大。它可以使用正则表达式(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 的{​​{1}}参数替换了找到的文件的路径。请注意,{}命令必须以分号结束,该分号必须进行转义(-exec)以防止shell对其进行解释。 -exec还可以合并多个分组(\;)测试操作表达式(find\(...\)):

    -o
  2. -a如果它是最近的GNU $ 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正则表达式(grep选项)并且只能输出匹配的部分(perl)。例如:

    -P
  3. 如果我们将所有这些粘合在一起,并使用bash变量以获得更好的可读性(臭名昭着的作弊以缩短最终的命令行),我们可以使用以下内容:

    -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.8re1="*/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 ) )和\0read)命令中使用-d $'\0'分隔符(而不是新行)。如果你有奇怪的目录名,这可能会有所帮助。

相关问题