简体   繁体   English

bash参数从两边展开

[英]Bash parameter expansion from both sides

I'm getting dollar values from a file into the variable in the form p=$1234.56, and would like remove $ and decimal places to get integer value in my conditional like我正在以 p=$1234.56 的形式从文件中获取美元值到变量中,并希望删除 $ 和小数位以在我的条件下获取整数值,例如

if [[ ${p%%.*} < 1000]]; then p=${p}0; fi

But this doesn't remove the $ sign, and I don't want to do it in 2 steps and modify actual variable, as I need $ for later use.但这并没有删除 $ 符号,我不想分两步完成并修改实际变量,因为我需要 $ 供以后使用。 How to get integer value regardless of number of digits ie ($2.2, $123456.1234...)?无论位数如何,如何获取整数值,即($2.2,$123456.1234...)?

Unfortunately, there is no way to avoid performing multiple parameter expansions if you need to remove multiple patterns, in the general case.不幸的是,在一般情况下,如果您需要删除多个模式,则无法避免执行多个参数扩展

In simple cases like this, you can avoid a temporary variable just by assigning back to the same variable.在像这样的简单情况下,您可以通过分配回同一个变量来避免临时变量。

p=${p#\$}
p=${p%.??}

In your specific scenario, of course, you can just replace any nonnumeric characters globally, and accept that the number will be multiplied by 100. You will obviously then need to multiply the number you compare against correspondingly.当然,在您的特定场景中,您可以全局替换任何非数字字符,并接受该数字将乘以 100。然后您显然需要将您比较的数字相应地相乘。

if [[ ${p//[!0-9]/} < 100000 ]]

Of course, for this to work, you need to be sure that your variable's value conforms to your expectations.当然,要使其工作,您需要确保变量的值符合您的期望。 If the value could have different numbers of decimal places depending on what a user passes in or where you read the input from, you need to perform additional normalizations, or just use a different approach entirely (frequently you'd pass your input to Awk or bc which support floating point math, unlike the shell).如果值可能具有不同的小数位数,具体取决于用户传入的内容或您从何处读取输入,您需要执行额外的规范化,或者完全使用不同的方法(通常您会将输入传递给 Awk 或bc支持浮点数学,与 shell 不同)。

However, the string substitution parameter expansion ${variable//pattern/replacement} is a Bash extension, and not portable to Bourne/POSIX sh .但是,字符串替换参数扩展${variable//pattern/replacement}是 Bash 扩展,不能移植到 Bourne/POSIX sh

It's not possible without modifying the var.不修改 var 是不可能的。 But you can use a subshell process with something like sed但是您可以使用带有sed之类的子shell 进程

if [[ $(sed 's/\$\([0-9]*\)\..*/\1/' <<< $p) < 1000 ]]; then p=${p}0; fi

Another option will be to use cut command to extract the substring before the dot (if any).另一种选择是使用cut命令提取点之前的子字符串(如果有的话)。 Then you can say something like:然后你可以这样说:

p='$1234.56'
[[ $(cut -d. -f1 <<< "${p#\$}") < 1000 ]] && p=${p}0
echo "$p"

BTW the expression [[ str1 < str2 ]] performs lexicographical comparison, meaning [[ 20 < 1000 ]] returns false because 20 sorts after 1000 in dictionary order.顺便说一句,表达式[[ str1 < str2 ]]执行字典比较,意思是[[ 20 < 1000 ]]返回false ,因为20按字典顺序1000之后排序。

If what you want to do is arithmetic comparison, you'll need to say [[ val1 -le val2 ]] or (( val1 < val2 )) such as:如果你想做的是算术比较,你需要说[[ val1 -le val2 ]](( val1 < val2 ))例如:

p='$1234.56'
[[ $(cut -d. -f1 <<< "${p#\$}") -le 1000 ]] && p=${p}0
echo "$p"

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

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