use*_*718 3 arrays variables bash eval indirection
Bash脚本用于从具有未知列的csv创建多个数组.
我正在尝试编写一个脚本来比较具有相似列的两个csv文件.我需要它来从其他csv找到匹配列并比较任何差异.踢球者是我希望脚本是动态的,允许输入任意数量的列,它仍然能够运行.我以为我有一个很好的计划来解决这个问题,但事实证明我遇到了语法错误.这是我需要比较的csv示例.
IP address, Notes, Nmap-SSH, Nmap-SMTP, Nmap-HTTP, Nmap-HTTPS,
10.0.0.1, , open, closed, open, open,
10.0.0.2, , closed, open, closed, closed,
Run Code Online (Sandbox Code Playgroud)
当我读取csv文件时,我打算寻找"IF列==打开;然后;用IP地址填充此列的数组"这将在这个场景中给出了4个列表,其中包含正在侦听所述端口的IP.然后,我可以将其与我的安全设备配置进行比较,以确保它已正确配置.最后,对于我来说,这就是我认为可以完成创建数组以供我稍后搜索的内容.但是当我尝试在数组名称中使用变量时,我遇到了麻烦.我的语法可以纠正,还是只有更好的方法来做这种事情?
#!/bin/bash
#
#
# This script compares config_cleaned_<ip>.txt output against ext_web_env.csv and outputs the differences
#
#
# Read from ext_web_env.csv file and create Array
#
FILENAME=./tmp/ext_web_env.csv
#
index=0
#
while read line
do
# How many columns are in the .csv?
varEnvCol=$(echo $line | awk -F, '{print NF}')
echo "columns = $varEnvCol"
# While loop to create array for each column
while [ $varEnvCol != 2 ]
do
# Checks to see if port is open; if so then add IP address to array
varPortCon=$(echo $line | awk -F, -v i=$varEnvCol '{print $i}')
if [ $varPortCon = "open" ]
then
arr$varEnvCol[$index]="$(echo $line | awk -F, '{print $1}')"
# I get this error message "line29 : arr8[194]=10.0.0.194: command not found"
fi
echo "arrEnv$varEnvCol is: ${arr$varEnvCol[@]}"
# Another error but not as important since I am using this to debug "line31: arr$varEnvCol is: ${arr$varEnvCol[@]}: bad substitution"
varEnvCol=$(($varEnvCol - 1))
done
index=$(($index + 1 ))
done < $FILENAME
Run Code Online (Sandbox Code Playgroud)
UPDATE
我也尝试使用eval命令,因为所有数据都将由其他脚本填充.
但我收到此错误消息:
./compare.sh:line 41:arr8 [83] = 10.0.0.83:找不到命令
这是我这个例子的新代码:
if [[ $varPortCon = *'open'* ]]
then
eval arr\$varEnvCol[$index]=$(echo $line | awk -F, '{print $1}')
fi
Run Code Online (Sandbox Code Playgroud)
mkl*_*nt0 13
arr$varEnvCol[$index]="$(...)"
Run Code Online (Sandbox Code Playgroud)
不能按照你期望的方式工作 - 你不能间接地分配shell变量- 通过扩展到变量名的表达式- 这样.
您试图解决eval
的问题也存在缺陷 - 见下文.
declare -n targetArray="arr$varEnvCol"
targetArray[index]=$(echo $line | awk -F, '{print $1}')
Run Code Online (Sandbox Code Playgroud)
declare "arr$varEnvCol"[index]="$(echo $line | awk -F, '{print $1}')"
Run Code Online (Sandbox Code Playgroud)
警告:这将适用于您的特定情况,但在其他情况下可能会失败 ; 继续阅读详细信息,包括基于的更强大但又繁琐的替代方案 read
.
@shellter在删除注释中eval
提到的基于解决方案的问题不仅出于安全原因(如他们所提到的那样),而且因为它在引用方面会变得非常棘手; 为了完整性,这是基于解决方案:eval
eval "arr$varEnvCol[index]"='$(echo $line | awk -F, '\''{print $1}'\'')'
Run Code Online (Sandbox Code Playgroud)
请参阅下面的说明.
bash
数组变量:bash 4.3+
:用于declare -n
有效地创建另一个变量的别名('nameref')如果可以的话,这是目前最好的选择:
declare -n targetArray="arr$varEnvCol"
targetArray[index]=$(echo $line | awk -F, '{print $1}')
Run Code Online (Sandbox Code Playgroud)
declare -n
有效地允许您通过另一个名称引用变量(无论该变量是否是数组),并且创建别名的名称可以是表达式(扩展字符串)的结果,如图所示.
bash 4.2-
:有几个选项,每个选项都有权衡注意:对于非数组变量,最好的方法是使用printf -v
.由于这个问题是关于数组变量的,因此不再进一步讨论这种方法.
read
:IFS=$'\n' read -r -d '' "arr$varEnvCol"[index] <<<"$(echo $line | awk -F, '{print $1}')"
Run Code Online (Sandbox Code Playgroud)
IFS=$'\n'
确保每个输入行中的前导和尾随空格保持不变.-r
防止对\
字符的解释.在输入中.-d ''
确保捕获所有输入,甚至是多行输入.
\n
字符.被剥夺了.-d ''
"arr$varEnvCol"[index]
扩展到变量 - 数组元素,在这种情况下 - 分配给; 请注意,引用index
数组下标中的变量不需要$
前缀,因为下标是在算术上下文中计算的,其中前缀是可选的.<<<
- 一个所谓的here-string - 将其参数发送到stdin
,其中read
输入来自.
[最简单,但可能会破裂]:使用declare
:
declare "arr$varEnvCol"[index]="$(echo $line | awk -F, '{print $1}')"
Run Code Online (Sandbox Code Playgroud)
declare
它意味着声明,而不是修改变量,但它适用于bash 3.x和4.x,具有下面提到的约束.)declare
.警告:INSIDE一个函数,只适用于LOCAL变量 - 你不能从函数内部引用shell-global变量(在函数外声明的变量).尝试这样做总是会创建一个LOCAL变量ECLIPSING shell-global变量.
[不安全和棘手]:使用eval
:
eval "arr$varEnvCol[index]"='$(echo $line | awk -F, '\''{print $1}'\'')'
Run Code Online (Sandbox Code Playgroud)
eval
在您完全控制正在评估的字符串的内容时使用; eval
将执行包含在字符串中的任何命令,可能会产生不需要的结果.eval
执行时发生,而不是在传递参数时发生的立即扩展. eval
'
.拼接成的\'
.eval
必须是双引号字符串 - 使用带有选择性引用的$
不带引号的字符串将不起作用,奇怪的是:
eval "arr$varEnvCol[index]"=...
eval arr\$varEnvCol[index]=...
归档时间: |
|
查看次数: |
2428 次 |
最近记录: |