首页 > 解决方案 > 为什么管道输出到 /dev/null 和 grep 会污染我的 bash 数组?

问题描述

我有两个 shell 脚本(Linux ,#!/bin/bash),一个有一些用于查找文本等的常用功能,另一个使用常用功能并做一些“实际”工作。

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

我不明白为什么会这样。有人有答案吗?如果您在使用脚本时 echo 或 printf ,只有当您将错误传递到 2>/dev/null 并 grep 输出时,它才会产生零差异。我已将脚本缩减为基本要素以显示问题。此外,通过将单行分开并将每个部分的输出分配给一个变量(请参阅 参考资料test3.sh),这个问题很容易解决,因此我不会拘泥于脚本编写或进一步的进展。我一直试图回答为什么LINES会发生污染。

测试1.sh

#!/bin/bash

declare -a LINES

echo "::: DECLARE ::: Length of [LINES] is: ${#LINES[@]}, :::Content of [LINES] is: ${LINES[@]}"

测试2.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: 

标签: arrayslinuxbashshell

解决方案


LINES是由 shell 填充的保留变量,其中包含终端窗口中可以容纳的行数。使用不同的变量名(shell 不使用它;请参阅Shell 变量),它会按预期工作。

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

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

shopt -u checkwinsize

推荐阅读