为什么 /dev/null 和 grep 会污染我的 bash 数组?



我有两个shell脚本(Linux,#!/bin/bash(,一个有一些用于查找文本等的通用函数,另一个利用公共函数并做一些"实际"工作。

当检查一个数组变量(test2.shoranges(以测试/查看它是否是一个数组(declare -p oranges 2>/dev/null | grep -q '^declare -a' && printf "$fmt" "oranges is an indexed array"(时,我偶然发现了另一个数组(LINEStest1.sh内部(突然被随机数">污染"的事实。

我不明白为什么会这样。有人有答案吗? 如果在使用脚本时回显或 printf,则只有将错误传送到 2>/dev/null 并 grep 输出时,它才产生零区别。我已经将脚本削减到最基本的内容来显示问题。 此外,通过将单行代码分开并将每个片段的输出分配给一个变量(见test3.sh(,可以轻松解决此问题,因此我不会停留在脚本编写或进一步的进展上。我一直在试图回答为什么会发生LINES污染。

test1.sh

#!/bin/bash
declare -a LINES
echo "::: DECLARE ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

test2.sh

#!/bin/bash
source ./test1.sh
declare -a oranges=()
echo "::: test2-1 ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

declare -p oranges 2>/dev/null
echo "::: test2-2 ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

declare -p oranges 2>/dev/null | grep -E -i '^declare -a'
echo "::: test2-3 ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

declare -p oranges 2>/dev/null | grep -E -i '^declare -a' && printf "$fmt" "oranges is an indexed array"
echo "::: test2-4 ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"
declare -p LINES
declare -p oranges 2>/dev/null | grep -E -i '^declare -a' && printf "$fmt" "oranges is an indexed array" || printf "$fmt" "oranges is not an indexed array"
echo "::: test2-5 ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

declare -p oranges 2>/dev/null
echo "::: test2-6 ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

运行时,将出现以下输出:

::: DECLARE ::: Length of [LINES] is: 0, :::Content of [LINES] is: 
::: test2-1 ::: Length of [LINES] is: 0, :::Content of [LINES] is: 
declare -a oranges=()
::: test2-2 ::: Length of [LINES] is: 0, :::Content of [LINES] is: 
declare -a oranges=()
::: test2-3 ::: Length of [LINES] is: 1, :::Content of [LINES] is: 81
declare -a oranges=()
::: test2-4 ::: Length of [LINES] is: 1, :::Content of [LINES] is: 81
declare -a LINES=([0]="81")
declare -a oranges=()
::: test2-5 ::: Length of [LINES] is: 1, :::Content of [LINES] is: 81
declare -a oranges=()
::: test2-6 ::: Length of [LINES] is: 1, :::Content of [LINES] is: 81

test3.sh - 解决方法

#!/bin/bash
source ./test1.sh
declare -a oranges=()
echo "::: test2-1 ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

someResult="$(declare -p oranges 2>/dev/null)"
thePattern="^declare -a"
nextResult=`grep -E -i "$thePattern" <<< "$someResult"` || nextResult=""
if [[ -n "$nextResult" ]]
then
echo "oranges is an indexed array"
else
echo "oranges is NOT an indexed array"
fi
echo "::: test2-2 ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

test3.sh 的输出..

$ ./test3.sh 
::: DECLARE ::: Length of [LINES] is: 0, :::Content of [LINES] is: 
::: test2-1 ::: Length of [LINES] is: 0, :::Content of [LINES] is: 
oranges is an indexed array
::: test2-2 ::: Length of [LINES] is: 0, :::Content of [LINES] is: 

LINES是一个保留变量,由 shell 填充,其中包含终端窗口中可能适合的行数。使用不同的变量名称(shell 不使用该名称;请参阅 shell 变量(,它将按预期工作。

正如 David C. Rankin 在他的评论中提到的,所有 UPPER-CASE 中的变量通常都保留给 shell,这就是为什么建议使用小写变量名的原因。

如果由于某种原因必须对变量使用名称 LINES,您可以通过以下命令禁用checkwinsize选项作为解决方法; 但这可能会产生副作用,我不能保证它会一直有效。

shopt -u checkwinsize

这可以解释以下行为:

d. 非交互式 shell 现在对 checkwinsize 的设置做出反应 并设置 前台作业退出后的行和列。

与 http://www.softpanorama.org/Scripting/Shellorama/Bash_history/bash43.shtml 相比

最新更新