简体   繁体   English

为什么管道输出到 /dev/null 和 grep 会污染我的 bash 阵列?

[英]Why does piping out to /dev/null and grep, pollute my bash array?

I have two shell scripts (Linux, #!/bin/bash ), one has some common functions in it for finding text etc., and the other making use of the common functions and doing some 'actual' work.我有两个 shell 脚本(Linux, #!/bin/bash ),一个有一些用于查找文本等的常用功能,另一个使用常用功能并做一些“实际”工作。

When examining an array variable ( oranges inside test2.sh ) to test/see if it's an array ( declare -p oranges 2>/dev/null | grep -q '^declare \-a' && printf "$fmt" "oranges is an indexed array" ), I stumbled across the fact that another array ( LINES inside test1.sh ) suddenly got " polluted " with a random number.检查数组变量( test2.sh中的oranges )以测试/查看它是否是数组( declare -p oranges 2>/dev/null | grep -q '^declare \-a' && printf "$fmt" "oranges is an indexed array" ),我偶然发现另一个数组( test1.sh中的LINES )突然被随机数“污染”了。

I cannot understand why this is happening.我不明白为什么会这样。 Anyone have an answer?有人有答案吗? It makes zero difference if you echo or printf when working with the scripts, only if you pipe errors to 2>/dev/null AND grep the output. It makes zero difference if you echo or printf when working with the scripts, only if you pipe errors to 2>/dev/null AND grep the output. I've cut-down the scripts to the bare essentials to show the problem.我已将脚本缩减为基本要素以显示问题。 Also, the problem is easily worked around by breaking the one-liner apart and assigning the output from each piece to a variable(see test3.sh ), so I'm not stuck on script writing or further progress.此外,通过将单线分开并将 output 从每个部分分配给一个变量(参见test3.sh ),这个问题很容易解决,所以我不会停留在脚本编写或进一步的进展上。 I am stuck on trying to answer why the pollution of LINES happens.我一直试图回答为什么会发生LINES的污染。

test1.sh测试1.sh

#!/bin/bash

declare -a LINES

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

test2.sh测试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[@]}"

And when run, the following output occurs:运行时会出现以下 output :

::: 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 - the workaround 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[@]}"

Output from test3.sh.. Output 来自 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 is a reserved variable populated by the shell with the number of rows that may fit in the terminal window. LINES是一个保留变量,由 shell 填充,其中的行数可能适合终端 window。 Use a different variable name (which isn't used by the shell; see Shell Variables ) and it'll work as expected.使用不同的变量名(shell 不使用该变量名;请参阅Shell 变量),它将按预期工作。

As David C.作为大卫 C。 Rankin mentioned in his comment, variables in all UPPER-CASE are generally reserved for the shell, which is why use of lower-case variable names is recommended. Rankin 在他的评论中提到,所有 UPPER-CASE 中的变量通常为 shell 保留,这就是为什么建议使用小写变量名的原因。

If you have to use the name LINES for your variable for some reason, you can disable the checkwinsize option by the following command as a workaround;如果出于某种原因必须为变量使用名称 LINES,则可以通过以下命令禁用checkwinsize选项作为解决方法; but that might have side-effects, and I can not guarantee that it'll always work.但这可能会产生副作用,我不能保证它会一直有效。

shopt -u checkwinsize

This may explain the behaviour:这可以解释这种行为:

d. d。 Non-interactive shells now react to the setting of checkwinsize and set LINES and COLUMNS after a foreground job exits.非交互式 shell 现在对 checkwinsize 的设置做出反应,并在前台作业退出后设置 LINES 和 COLUMNS。

from http://www.softpanorama.org/Scripting/Shellorama/Bash_history/bash43.shtml来自http://www.softpanorama.org/Scripting/Shellorama/Bash_history/bash43.shtml

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM