[英]Variable Manipulation not working as expected in macOS bash script
鉴于:
itemName='boo\boo\1\7\064.txt'
我想在删除不可打印的同时将八进制转换为可打印的。 问题:我不想删除像 \\b 这样的反斜杠 alpha。 结果应该是:
newItemName='boo\boo4.txt'
我不明白为什么 sed 语句的一部分不能正常工作:
newItemName="$(printf "%s" "$itemName" | sed -E 's/(\\[0-7]{1,3})/'"$(somevar="&";printf "${somevar:1}";)"'/g' | tr -dc '[:print:]')"
我使用了somevar="&"; 而不是直接访问&所以我可以使用变量操作。
搜索语句s/(\\[0-7]{1,3})/工作正常。
在 printf 中,如果我使用$somevar或${somevar:0}而不是${somevar:1}我会按预期得到原始字符串(例如 \\064)。 不起作用的是${somevar:1} 。 这些也不起作用: ${somevar/\\/}或${somevar//\\/} 。
山姆; 好久不见! 这里的问题是评估的顺序。 所有 shell 表达式,包括$(somevar="&";printf "${somevar:1}";)
,都会在 sed 启动之前进行评估。 因此, somevar
不是正则表达式匹配的字符串,它只是一个文字&符号。 这意味着${somevar:1}
只是一个空字符串,你最终只是运行sed -E 's/(\\\\[0-7]{1,3})//g'
。
您需要一种方法来获取匹配的字符串并对其运行计算(在匹配之后),而 sed 不够灵活,无法执行此操作。 但是 perl 是。 perl 有一个s
运算符,类似于 sed 的运算符,但使用e
选项时,替换将作为 perl 表达式执行,而不仅仅是文字字符串。 试试这个:
newItemName="$(printf "%s\n" "$itemName" | perl -pe 's/\\([0-7]{1,3})/chr oct $1/eg' | tr -dc '[:print:]')"
我对变量操作的工作方式有什么误解?
我相信您误解了sed
工作原理。
在替换字符串中使用&
字符时,将替换为匹配的整个字符串。 请参阅此 sed 介绍。
现在关于${var:offset}
参数扩展:
somevar=&
printf "$somevar"
会打印&
。 然后:
printf "${somevar:1}"
将提取从偏移量 1 开始到字符串末尾的子字符串。 第一个字符在偏移量 0 处,因此在偏移量 1 处没有字符,因为 out 变量somevar
有一个字符。 所以它不会打印任何东西。
printf "${somevar:0}"
将打印从偏移量 0 开始到字符串末尾的子字符串。 所以整个字符串。 所以${somevar:0}
等于$somevar
。 它将打印&
。
所以:
$(somevar="&";printf "${somevar:1}";)
扩展为${somevar:1}
,因为${somevar:1}
扩展为${somevar:1}
。 所以你 sed 命令看起来像这样:
sed -E 's/(\\[0-7]{1,3})//g'
sed 命令多次替换\\
字符后跟数字0-7
一到 3 次。 它做你想做的。
现在,如果它是${somevar:0}
那么:
$(somevar="&";printf "${somevar:0}";)
扩展为&
,因此您的 sed 命令将如下所示:
sed -E 's/(\\[0-7]{1,3})/&/g'
所以它会用\\\\[0-7]{1,3}
代替它自己。 IE。 它什么都不做。
您可以取消-E
选项和(...)
反向引用,而只需使用 posixly 兼容的sed
:
sed 's/\\[0-7]\{1,3\}//g'
有没有更简单的方法来做到这一点?
你的方法看起来不错。 您可以使用here 字符串代替 printf ,并且可以根据需要加强 sed 以更好地匹配八进制数:
newItemName="$(
<<<"$itemName" sed 's/\\\([0-3][0-7]\{0,2\}\|[0-7]\{1,2\}\)//g' |
tr -dc '[:print:]'
)"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.