如何让grep在包含\n的Bash变量中正常工作?
问题:如何用grep过滤含转义
\n的Bash变量? 问题重现
场景1:Here-doc定义变量(grep正常工作)
当用Here-doc方式定义多行变量时,grep可以正常按行过滤包含指定关键词的内容:
test_string=$(cat <<END hello world test bar hello END ) echo -e "$test_string" filter_string="$(grep "hello" <<< "$test_string")" echo -e "$filter_string"
执行输出:
# test_string=$(cat <<END hello world test bar hello END ) # echo -e "$test_string" hello world test bar hello # filter_string="$(grep "hello" <<< "$test_string")" # echo -e "$filter_string" hello bar hello #
场景2:用\n拼接变量(grep失效)
但如果通过\n转义字符拼接生成多行变量,grep无法按预期过滤,会输出所有内容:
test_string="hello\nworld\ntest\nbar hello" echo -e "$test_string" filter_string="$(grep "hello" <<< "$test_string")" echo -e "$filter_string"
错误输出:
# test_string="hello\nworld\ntest\nbar hello" # echo -e "$test_string" hello world test bar hello # filter_string="$(grep "hello" <<< "$test_string")" # echo -e "$filter_string" hello world test bar hello #
动态拼接的场景
实际脚本中可能是通过多次拼接生成变量:
test_string="hello" test_string="${test_string}\nworld" test_string="${test_string}\ntest" test_string="${test_string}\nbar hello"
拼接其他变量的问题
如果拼接时包含其他变量,还会遇到变量无法展开的问题:
other_string="world" test_string="hello" test_string+=$'\n${other_string}' test_string+=$'\ntest' test_string+=$'\nbar hello' echo "$test_string"
输出:
hello ${other_string} test bar hello
解决方案
方法1:生成变量时直接使用真实换行(推荐)
Bash中可以用$'...'语法解析转义字符,生成真实的换行符。拼接变量时,要注意将待展开的变量放在双引号中,避免单引号阻止变量解析:
other_string="world" test_string="hello" test_string+=$'\n'"$other_string" # 用$'\n'生成真实换行,变量放在双引号中展开 test_string+=$'\ntest' test_string+=$'\nbar hello' echo "$test_string"
此时test_string中存储的是真实换行符,直接用grep过滤即可正常工作:
filter_string="$(grep "hello" <<< "$test_string")" echo "$filter_string"
输出会正确显示包含hello的行:
hello bar hello
方法2:将现有转义\n转换为真实换行后过滤
如果已经有了存储着转义\n的变量,可以用echo -e或printf将其转换为真实换行,再传给grep:
test_string="hello\nworld\ntest\nbar hello" # 用echo -e转换转义字符 filter_string="$(echo -e "$test_string" | grep "hello")" echo "$filter_string" # 或用printf更可靠 filter_string="$(printf "%b" "$test_string" | grep "hello")" echo "$filter_string"
问题根源
用"hello\nworld"定义变量时,\n是字面量的\和n两个字符,不是真实的换行符。当用<<< "$test_string"传给grep时,grep会把整个内容当成一行处理,只要该行包含hello就会输出全部内容;而Here-doc定义的变量中是真实的换行符,grep会按行分割处理。
内容的提问来源于stack exchange,提问作者stackbiz
相关产品推荐
相关产品推荐

