找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
广告投放联系QQ68610888
查看: 493|回复: 4

经验只谈:shell中哪些参量要用双引号、哪些绝不能用双引号,自己也会忘记,留贴加强

[复制链接]
发表于 2022-1-9 11:15 | 显示全部楼层 |阅读模式
赋值一个参量时,最好都使用双引号:比如 A=“张 三” ,因为参量中带有空格,有双引号时,”张 三“视为一个整体,而无双引号时,仅 A=张 有效,三无效,运行报错。
为什么参量要用空格?举例:
A="1 2 3 4 5"
for i in $A
do
echo $i
done

于是又引出另外一个问题,什么地方的参量不能用空格,还是上面的例子:
A="1 2 3 4 5"
for i in $A
do
echo $i
done
运行结果是:

1
2
3
4
5

$A改为加双引号:
A=”1 2 3 4 5“
for i in "$A"
do
echo $i
done
运行结果是:

1 2 3 4 5




纠结其原因是,for i in $A时,shell会把其中空格替换为换行符,逐行读出里面的内容然后传递给do后面的命令。而for i in ”$A“时,”$A“作为一个整体,里面的空格不会被替换。


总结就是:除非特殊情况,作为命令运行时,不能使用双引号。比如
MAC=“01:59:74:64:46:EC” ; iptables -I FORWARD -m mac --mac-source $MAC -j DROP

运行正常。
MAC=“01:59:74:64:46:EC” ; iptables -I FORWARD -m mac --mac-source "$MAC" -j DROP
运行报错:iptables v1.8.3 (legacy): Invalid match name " mac --mac-source 01:59:74:64:46:EC" (28 chars max) ,是因为双引号也被作为命令的一部分运行了。

再例如:
PORT="3003" ; /etc/AdGuardHome/AdGuardHome -p $PORT -l /var/log/AdGuardHome.log
运行正常。
PORT="3003" ; /etc/AdGuardHome/AdGuardHome -p "$PORT" -l /var/log/AdGuardHome.log
运行报错。

另外,条件比较时,最好用双引号,比如:
[ $A == 1 ] && echo "yes"
运行报错unknown operand,因为不存在A参量。
[ "$A" == 1 ] && echo "yes"
运行不报错

而条件判断时,用不用双引号,结果截然相反:
[ -n $A ] && echo "yes"
运行结果是:yes。明显不对,都不存在A参量。
[ -n "$A" ] && echo "yes"
运行结果没有输出,正确。

评分

参与人数 1恩山币 +1 收起 理由
hzqim + 1 一看就是觉得高端、大气、上档次!

查看全部评分

我的恩山、我的无线 The best wifi forum is right here.
发表于 2022-1-9 12:12 | 显示全部楼层
谢谢经验分享!要好好玩路由器绕不开script.
我的恩山、我的无线 The best wifi forum is right here.
回复

使用道具 举报

发表于 2022-5-18 23:16 | 显示全部楼层
谢谢经验分享!我也正在研究脚本,一些脚本能实现路由器很多功能!
我的恩山、我的无线 The best wifi forum is right here.
回复

使用道具 举报

发表于 2022-5-26 18:55 | 显示全部楼层
本帖最后由 23Xor 于 2022-5-26 18:57 编辑

bash中可以通过改变$IFS改变分隔符
  1. IFS=''
  2. A="1 2 3 4 5"
  3. for i in $A
  4. do
  5. echo $i
  6. done
复制代码
输出结果:
  1. 1 2 3 4 5
复制代码

$IFS也可以是别的:
  1. IFS='3'
  2. A="1 2 3 4 5"
  3. for i in $A
  4. do
  5. echo $i
  6. done
复制代码
输出结果:
  1. 1 2
  2. 4 5
复制代码



我的恩山、我的无线 The best wifi forum is right here.
回复

使用道具 举报

发表于 2022-5-26 19:56 | 显示全部楼层
本帖最后由 23Xor 于 2022-5-26 20:04 编辑
另外,条件比较时,最好用双引号,比如:
[ $A == 1 ] && echo "yes"
运行报错unknown operand,因为不存在A参量。
[ "$A" == 1 ] && echo "yes"
运行不报错

而条件判断时,用不用双引号,结果截然相反:
[ -n $A ] && echo "yes"
运行结果是:yes。明显不对,都不存在A参量。
[ -n "$A" ] && echo "yes"
运行结果没有输出,正确。

其实这个是shell的变量机制、引号的作用、括号的作用共同造成的。
shell的变量机制:执行命令前找出变量并替换,再执行替换后的命令
引号的作用:标记引号内的东西是字符串
括号的作用:中括号相当于命令test

现在我们分析这几条命令:
  1. [ $A == 1 ] && echo "yes"
复制代码

如果A没定义,执行的是:
  1. [  == 1 ] && echo "yes"
复制代码
test表示,“ == 1 ”是什么鬼?这表达式我看不懂,于是给你报了个错
  1. [ "$A" == 1 ] && echo "yes"
复制代码
如果A没定义,执行的是:
  1. [ "" == 1 ] && echo "yes"
复制代码
test表示,这回能看懂了。
问题是为什么test能看懂“ "" == 1 ”这个玩意?正是因为双引号标记了引号内的东西是个字符串。虽然test的内部最后看到的其实都是“ 啥也没有 == 1 ”,但是“被标记的啥也没有”和“没被标记的啥也没有”是不一样的,“被标记的啥也没有”是字符串,准确的说,是“空字符串”,但是“没被标记的啥也没有”就真的啥也不是。
我们再看这个:
  1. [ -n $A ] && echo "yes"
复制代码
为啥$A不存在它也为真?
这里我们要澄清一下,-n的逻辑不是看变量存不存在,而是-n的参数是否为空字符串,是空字符串,test返回假,否则返回真。
还有,test命令的选项默认是-n,如果你没给选项,选项就是-n。
如果A没定义,执行的是:
  1. [ -n  ] && echo "yes"
复制代码
这里的逻辑就十分神奇:如果-n后面不跟别的东西,他就不配做一个选项!那么现在-n不是选项,谁是选项呢?还是-n!因为选项默认是-n,如果你没给选项,选项就是-n。不过,此-n非彼-n,我们现在执行的命令等效于:
  1. [ -n -n ] && echo "yes"
复制代码
俩-n!!!这条命令到底是干什么的???答案很简单,就是判断“-n”自己是不是空字符串,他当然不是,所以test返回了真,yes能够成功输出。
那么我们再看看加了引号的命令:
  1. [ -n "$A" ] && echo "yes"
复制代码
如果A没定义,执行的是:
  1. [ -n "" ] && echo "yes"
复制代码
如前面所说,""是“被标记的啥也没有”,正宗的空字符串,所以test返回假,yes不能成功输出。

shell,好生神奇!

为啥shell变量的设计和其他编程语言不一样?因为在其他语言里,变量是一个指针,调用变量就是获取指针指向的数据。而在shell里,你执行的脚本只不过是shell这个程序的一个超级巨大的“参数”,shell不过是在“看脚本办事”,而shell的变量只是为了便于你理解才设计成和其他语言差不多的逻辑形式,实际上与一般编程语言中以指针为基础的变量有诸多不同,毕竟shell语言可以说是一种“语言套语言”。

我的恩山、我的无线 The best wifi forum is right here.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

有疑问请添加管理员QQ86788181|手机版|小黑屋|Archiver|恩山无线论坛(常州市恩山计算机开发有限公司版权所有) ( 苏ICP备05084872号 )

GMT+8, 2024-3-29 09:44

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

| 江苏省互联网有害信息举报中心 举报信箱:js12377 | @jischina.com.cn 举报电话:025-88802724 本站不良内容举报信箱:68610888@qq.com 举报电话:0519-86695797

快速回复 返回顶部 返回列表