arrays - 为什么管道输出到 /dev/null 和 grep 会污染我的 bash 数组?
问题描述
我有两个 shell 脚本(Linux ,#!/bin/bash
),一个有一些用于查找文本等的常用功能,另一个使用常用功能并做一些“实际”工作。
在检查数组变量(oranges
inside test2.sh
)以测试/查看它是否是数组(declare -p oranges 2>/dev/null | grep -q '^declare \-a' && printf "$fmt" "oranges is an indexed array"
)时,我偶然发现了另一个数组(LINES
inside 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:
解决方案
LINES
是由 shell 填充的保留变量,其中包含终端窗口中可以容纳的行数。使用不同的变量名(shell 不使用它;请参阅Shell 变量),它会按预期工作。
正如 David C. Rankin 在他的评论中提到的,所有 UPPER-CASE 中的变量通常都是为 shell 保留的,这就是为什么建议使用小写变量名的原因。
如果出于某种原因必须为变量使用名称 LINES,则可以通过checkwinsize
以下命令禁用该选项作为解决方法;但这可能会产生副作用,我不能保证它会一直有效。
shopt -u checkwinsize
推荐阅读
- javascript - Node.js - https.get() 和 JSON.parse() 使服务器崩溃
- php - XML 递归迭代分组
- vba - 如何点击页面中的所有链接,一一返回?
- apache-kafka - Kafka:SASL_SSL + ACL 可以生产但不能消费
- sql - 如何连接不区分大小写的相同数据的 2 个字段
- ios - 对 SwiftUI FetchRequest 的更改不会触发视图刷新?
- rust - 迭代 BTreeMap 和 &BTreeMap 的区别
- python - Python:在任何计算机/操作系统上查找 CSV 文件
- java - 如何在 Android 中连接到 websocket
- csv - 将 CSV 从 S3 加载到 AWS RDS Aurora MySQL Serverless