聊一聊shell中字符串 单引号 双引号以及执行字符串命令中的坑

一直以来对shell中字符串的了解就是单引号和双引号内的都是字符串,双引号内字符串可以被替换成变量,单引号就是原字符串输出,今天在开发一个hdfs跨集群拷贝数据脚本时候发现shell echo出来同样的命令手动执行可以执行,在shell内通过${cmd}方式却报错,通过sh -x a.sh才发现问题产生的根源,具体如下:

众所周知hdfs在集群内部拷贝文件命令如下:

hdfs dfs -cp src_path target_path

我这里是跨集群拷贝,集群的配置文件中集群部门的同事由于种种原因不愿意配置别的集群的nameservice,我要实现最简单的方式就是通过-D将这些参数传进去,完整命令如下:

hdfs dfs -Ddfs.nameservices='ns1,ns2' -Ddfs.ha.namenodes.ns2='nn1,nn2' -Ddfs.namenode.rpc-address.ns2.nn1='master01:8888' -Ddfs.namenode.rpc-address.ns2.nn2='master02:8888' -Ddfs.client.failover.proxy.provider.ns2='org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider' -cp src_path hdfs://ns2/target_path

上述命令中ns1是我们部门集群,ns2是别的部门的集群,需要将我们部门的数据拷贝到别的集群,上述命令手动执行是不会有任何问题的,在shell中使用时候我是这么使用的,部分片段如下:

hdfs_conf="-Ddfs.nameservices='ns1,ns2' -Ddfs.ha.namenodes.ns2='nn1,nn2' -Ddfs.namenode.rpc-address.ns2.nn1='master01:8888' -Ddfs.namenode.rpc-address.ns2.nn2='master02:8888' -Ddfs.client.failover.proxy.provider.ns2='org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider'"
cp_cmd="hdfs dfs ${hdfs_conf} -cp src_path hdfs://ns2/target_path"
# 输出一下命令
echo ${cp_cmd}
# 执行命令
${cp_cmd}

输出信息如下:

hdfs dfs -Ddfs.nameservices='ns1,ns2' -Ddfs.ha.namenodes.ns2='nn1,nn2' -Ddfs.namenode.rpc-address.ns2.nn1='ns1:8888' -Ddfs.namenode.rpc-address.ns2.nn2='ns2:8888' -Ddfs.client.failover.proxy.provider.ns2='org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider' -cp src_path hdfs://ns2/target_path
cp: Couldn't create proxy provider null

看echo出来的命令是没有任何问题的,但是却提示provider为null,导致执行失败,添加-x参数以后输出如下:

+ hdfs_conf='-Ddfs.nameservices='\''ns1,ns2'\'' -Ddfs.ha.namenodes.ns2='\''nn1,nn2'\'' -Ddfs.namenode.rpc-address.ns2.nn1='\''ns1:8888'\'' -Ddfs.namenode.rpc-address.ns2.nn2='\''ns2:8888'\'' -Ddfs.client.failover.proxy.provider.ns2='\''org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider'\'''
+ cp_cmd='hdfs dfs -Ddfs.nameservices='\''ns1,ns2'\'' -Ddfs.ha.namenodes.ns2='\''nn1,nn2'\'' -Ddfs.namenode.rpc-address.ns2.nn1='\''ns1:8888'\'' -Ddfs.namenode.rpc-address.ns2.nn2='\''ns2:8888'\'' -Ddfs.client.failover.proxy.provider.ns2='\''org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider'\'' -cp src_path hdfs://ns2/target_path'
+ echo hdfs dfs '-Ddfs.nameservices='\''ns1,ns2'\''' '-Ddfs.ha.namenodes.ns2='\''nn1,nn2'\''' '-Ddfs.namenode.rpc-address.ns2.nn1='\''ns1:8888'\''' '-Ddfs.namenode.rpc-address.ns2.nn2='\''ns2:8888'\''' '-Ddfs.client.failover.proxy.provider.ns2='\''org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider'\''' -cp src_path hdfs://ns2/target_path
hdfs dfs -Ddfs.nameservices='ns1,ns2' -Ddfs.ha.namenodes.ns2='nn1,nn2' -Ddfs.namenode.rpc-address.ns2.nn1='ns1:8888' -Ddfs.namenode.rpc-address.ns2.nn2='ns2:8888' -Ddfs.client.failover.proxy.provider.ns2='org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider' -cp src_path hdfs://ns2/target_path
+ hdfs dfs '-Ddfs.nameservices='\''ns1,ns2'\''' '-Ddfs.ha.namenodes.ns2='\''nn1,nn2'\''' '-Ddfs.namenode.rpc-address.ns2.nn1='\''ns1:8888'\''' '-Ddfs.namenode.rpc-address.ns2.nn2='\''ns2:8888'\''' '-Ddfs.client.failover.proxy.provider.ns2='\''org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider'\''' -cp src_path hdfs://ns2/target_path
cp: Couldn't create proxy provider null

相比到这里各位应该看明白了,虽然echo输出来的命令是正确的,但是在执行过程中,shell会给程序添加单引号,结果单引号就很多了,其中有转义,导致最终真实执行的命令很乱。

此时如果要执行这个命令,可以把最后的${cp_cmd}修改为eval ${cp_cmd},eval会把中间的单引号和双引号全部去掉,此时执行就是我想要的结果,感兴趣的朋友可以试着自己debug试试。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值