如何只打印 shell 脚本中定义的变量?

如何只打印 shell 脚本中定义的变量?

让我们假设一些bash外壳脚本喜欢:

#!/bin/bash 
a=3
b=7
set -o posix
set

在这种情况下,执行变量set或其他一些命令打印环境变量( env, declare... 等) 输出 myab变量,加上一个很多变数(和功能)来自环境(PATHPWDTEMP...等)。

有没有办法只打印那些已经存在的变量在脚本期间定义身体?

答案1

您可以将变量列表存储在脚本开头,并将其与脚本中某处的值进行比较。请注意,类似命令的输出set并不是明确的:类似命令set | sed 's/=.*//'不适用于值包含换行符的变量。 (在 bash 中,它实际上适用于字符串变量,但不适用于数组,并且它还显示函数代码。)我认为以下代码片段可靠地列出了当前定义的变量(按字母顺序排列):

variables=$(tmp=$(declare -p +F); declare () { echo "${2%%=*}"; }; eval "$tmp")

因此,initial_variables=…在脚本的开头设置,并与后面的值进行比较。除了echo直接对列表进行操作之外,您还可以使用其他方法。

initial_variables=" $(tmp=$(declare -p +F); declare () { echo "${2%%=*}"; }; eval "$tmp") "
( tmp=$(declare -p +F)
  declare () {
    case "$initial_variables" in
      *" $2 "*) :;; # this variable was present initially
      *) eval "set -- \"\$$2\" \"\$2\""; echo "locally defined $2=$1";;
    esac
  }
)

答案2

我作弊了:我只是将不想列出的变量重命名为以字母“aaa”开头的变量(例如我从另一个文件中获取的变量),然后调用内置命令compgen -v。然后我按数字我知道脚本中存在的变量。

例如,我从另一个文件中获取了两个以 aaa 开头的变量,并且我的脚本中有三个随机命名的变量(首字母范围从从头到尾),通过将这个简单的命令放入我的脚本中,我可以在输出中仅列出这三个变量:

compgen -v | tail -n 3

编辑:
如果我不知道脚本中有多少个变量:那么我可以这样做:

compgen -v | awk '$0 == "aaauser" {i=1;next};i && i++ <= 100'

在哪里AAA用户是个最后按字母顺序排列我从其他文件中获取的变量。您可以将其应用于任何已知变量。

答案3

comm使用,和过程替换的2 行策略compgen -v...

ENVVARS="$(compgen -v)"
    :
  <script>
    :
comm -1 -3 <(sort <<< "$ENVVARS") <(compgen -v | sort)

comm --help...

Usage: comm [OPTION]... FILE1 FILE2

Compare sorted files FILE1 and FILE2 line by line.

With no options, produce three-column output.  Column one contains
lines unique to FILE1, column two contains lines unique to FILE2, and
column three contains lines common to both files.

    -1              suppress lines unique to FILE1
    -2              suppress lines unique to FILE2
    -3              suppress lines that appear in both files

comm命令允许我们从脚本末尾的总环境变量集中“减去”传递给脚本的环境变量集,只留下脚本创建的环境变量。

选项 -1 和 -3 丢弃除此脚本中创建的变量(即“文件 2”中的行)之外的所有变量。 Bash Process Substitution<(...)用于列出变量并对其进行排序,然后将输出视为文件。

请注意,不包括声明为函数本地的变量,因为它们超出了主脚本的范围。

可以使用相同的技术来列出函数内创建的变量。然而,在这种情况下,命名此类变量以下划线开头(_)并在调用中添加下划线前缀的约定compgen可能更理想......

LOCALVARS="$(compgen -v _)"

答案4

这是获取所有当前定义的变量名的排序列表的便携式方法:

v(){ set "${IFS+IFS=\$2}" "$IFS"; unset IFS
     set  $(set|sed -n '/^[_[:alpha:]][[:alnum:]]*=/s/=.*//p'|sort -u) "$@"
     while [ "$#" -gt 2 ] 
     do    eval '[ "${'$1'+1}" = 1 ]' && 
           echo "$1"; shift
     done; eval "$1"
}

该列表被echo编辑到v()的标准输出 - 每行一个名称。因为它是sorted 的,所以它是以后与类似生成的列表进行比较的良好候选者,就像您可能使用comm或类似的那样。该列表有意排除$IFS- 这是因为 - 设置或未设置 -$IFS总是实际上,因此必须在这样的列表中给出。可以这样改变:

set "${IFS+IFS=\$2}" "$IFS"; IFS='
'; set $(set|... 

...但那只会永远包括无论是否设置,它都在列表中 - 这让我回到了之前的观点......

相关内容