shell数组赋值问题

sh/bash/dash/ksh/zsh等Shell脚本
头像
naturalaw
帖子: 1360
注册时间: 2011-09-06 22:04

Re: shell数组赋值问题

#16

帖子 naturalaw » 2011-09-29 0:49

文件名中空格是*nix操作系统的机制问题,看来确实如此。
可以说是,也可以说不是。不知道你有没读过shell 13问,其中有关于IFS的问题。
  • The eternal law
头像
vinoca
帖子: 59
注册时间: 2011-03-21 18:30

Re: shell数组赋值问题

#17

帖子 vinoca » 2011-09-29 11:14

naturalaw 写了:
文件名中空格是*nix操作系统的机制问题,看来确实如此。
可以说是,也可以说不是。不知道你有没读过shell 13问,其中有关于IFS的问题。
这个和IFS变量没有关系吧?IFS只是shell的特殊变量,而文件名空格的处理在编译器和库里面。昨天做过进一步的验证,确实是gcc的机制。其实文件名中有空格处理起来很麻烦,如果自己分析的话。以前在Windows中也写过处理命令行参数的子程序,如果考虑所有情况将是一个大的分支树。 :em20
可以用这片代码来验证此问题:

代码: 全选

#include <stdio.h>

int main(int argc,char * argv[])
{
	 int i;
	 printf ("argc = %d\n",argc);
	 for (i=0;i<argc;i++)
	 	printf ("argv[%d] = %s\n",i,argv[i]);
	 return;
}

tusooa
帖子: 6548
注册时间: 2008-10-31 22:12
系统: 践兔
联系:

Re: shell数组赋值问题

#18

帖子 tusooa » 2011-09-29 20:38

vinoca 写了:
eexpress 写了:传过去的时候,"$i"就可以了。一次性传递字符串,可以使用\"或者\'包括每一个项目。
如果接收的是bash脚本,使用$@处理传入的就是,自动分割带空格和特殊字符的参数的。不用操心。

改文件名,比较不是长久之计。一定要这样,你可以使用incron监视目录,进入目录的文件,自动改名,处理掉空格和特殊字符(:|?\/)等。
嗯,刚做了测试,目录中有4个文件:

代码: 全选

类似爱情.mp3  伤不起.mp3  映山红.mp3  雨蝶.ape
然后:

代码: 全选

a=(类似爱情.mp3 "伤不起.mp3 映山红.mp3" 雨蝶.ape)
echo ${a[@]}
echo ${#a[@]}
mplayer ${a[@]}
有3个数组元素,mplayer会正常播放这4个歌曲。引号会被忽略,空格等空白字符是参数分隔的标志。很明显,bash在给数组赋值时把引号剥离了,再传入:

代码: 全选

 a=(类似爱情.mp3 "\"伤不起.mp3 映山红.mp3\"" 雨蝶.ape)
mplayer会将第2个数组元素解析为"伤不起.mp3和映山红.mp3",空格仍然是特殊字符,而引号则成了一般字符。其它程序未做测试。
文件名中空格是*nix操作系统的机制问题,看来确实如此。
你那$@,${a[@]}啥的,都要加引号。

代码: 全选

] ls -ld //
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: shell数组赋值问题

#19

帖子 fnan » 2011-09-29 20:47

引号是保护空格等特殊字符的,不管用不用数组,合理运用引号才是关键。
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: shell数组赋值问题

#20

帖子 fnan » 2011-09-29 21:10

kose3@kose3-desktop:~/b$ ls
a bmk.007 amk.001 amk.002 amk.003 amk.004 amk.005 amk.006(七个文件,a bmk.007带空格)
kose3@kose3-desktop:~/b$ IFS=$'\n' (改变IFS)
kose3@kose3-desktop:~/b$ f=($(ls))(数组赋值)
kose3@kose3-desktop:~/b$ echo ${f[*]}(无引号)
a bmk.007 amk.001 amk.002 amk.003 amk.004 amk.005 amk.006
kose3@kose3-desktop:~/b$ echo "${f[*]}" (有引号)
a bmk.007
amk.001
amk.002
amk.003
amk.004
amk.005
amk.006
kose3@kose3-desktop:~/b$ echo ${#f[*]}
7(数组元素数量)
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
头像
vinoca
帖子: 59
注册时间: 2011-03-21 18:30

Re: shell数组赋值问题

#21

帖子 vinoca » 2011-09-30 9:52

tusooa 写了: 你那$@,${a[@]}啥的,都要加引号。
经测试,加引号与不加引号没有区别。引号只是shell最初一层的“保护”,防止一些字符被转义,特别是空白字符,这里已经没有引号(\"处)之外的空白字符,所以结果是这样。
头像
vinoca
帖子: 59
注册时间: 2011-03-21 18:30

Re: shell数组赋值问题

#22

帖子 vinoca » 2011-09-30 10:17

fnan 写了:kose3@kose3-desktop:~/b$ ls
a bmk.007 amk.001 amk.002 amk.003 amk.004 amk.005 amk.006(七个文件,a bmk.007带空格)
kose3@kose3-desktop:~/b$ IFS=$'\n' (改变IFS)
kose3@kose3-desktop:~/b$ f=($(ls))(数组赋值)
kose3@kose3-desktop:~/b$ echo ${f[*]}(无引号)
a bmk.007 amk.001 amk.002 amk.003 amk.004 amk.005 amk.006
kose3@kose3-desktop:~/b$ echo "${f[*]}" (有引号)
a bmk.007
amk.001
amk.002
amk.003
amk.004
amk.005
amk.006
kose3@kose3-desktop:~/b$ echo ${#f[*]}
7(数组元素数量)
实战派,赞。思考,并引发别人思考,再赞!
这里有无引号的情况,如实地再现了shell处理引号内特殊字符的方式和IFS对数组等默认要用到shell内部提供分隔字符的影响。
当然,在这里加引号显然是不行的,这样传给程序的就成了一个参数了。经测试实际结果也是这样。因为传给程序和传给echo是不一样的,echo会对引号做一次剥离。
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: shell数组赋值问题

#23

帖子 fnan » 2011-09-30 17:31

kose3@kose3-desktop:~$ f=("a c.wav" "b.wav")
kose3@kose3-desktop:~$ mplayer "${f[@]}"
MPlayer SVN-r1.0~rc3+svn20090426-4.4.3 (C) 2000-2009 MPlayer Team
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.

Playing a c.wav. (正确处理了空格)
Audio only file format detected.
==========================================================================
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 11025 Hz, 1 ch, u8, 88.2 kbit/100.00% (ratio: 11025->11025)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================
AO: [pulse] 11025Hz 1ch u8 (1 bytes per sample)
Video: no video
Starting playback...
A: 0.1 (00.1) of 0.4 (00.4) ??,?%

Playing b.wav. (播放第二个wave文件)
Audio only file format detected.
==========================================================================
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 11025 Hz, 1 ch, u8, 88.2 kbit/100.00% (ratio: 11025->11025)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
==========================================================================
AO: [pulse] 11025Hz 1ch u8 (1 bytes per sample)
Video: no video
Starting playback...
A: 0.2 (00.1) of 0.5 (00.4) ??,?%

Exiting... (End of file)
kose3@kose3-desktop:~$
#你是怎么测试的?
加个参数输入测试:
kose3@kose3-desktop:~$ f=("a b" "c")
kose3@kose3-desktop:~$ cat tmp.sh
#!/bin/bash

echo $#
kose3@kose3-desktop:~$ ./tmp.sh ${f[@]}
3
kose3@kose3-desktop:~$ ./tmp.sh "${f[@]}"
2
kose3@kose3-desktop:~$
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
头像
vinoca
帖子: 59
注册时间: 2011-03-21 18:30

Re: shell数组赋值问题

#24

帖子 vinoca » 2011-09-30 17:58

嗯,是这样:

代码: 全选

[aituroi@Ioxeemoo xin1108]$ ls
类似爱情.mp3  伤不起.mp3  映山红.mp3  雨蝶.ape
[aituroi@Ioxeemoo xin1108]$ f=($(ls))
[aituroi@Ioxeemoo xin1108]$ echo ${f[*]}
类似爱情.mp3 伤不起.mp3 映山红.mp3 雨蝶.ape
[aituroi@Ioxeemoo xin1108]$ echo "${f[*]}"
类似爱情.mp3
伤不起.mp3
映山红.mp3
雨蝶.ape
[aituroi@Ioxeemoo xin1108]$ mplayer "${f[*]}"
MPlayer2 2.0 (C) 2000-2011 MPlayer Team
160 个音频和 350 个视频编解码器

正在播放 类似爱情.mp3
伤不起.mp3
映山红.mp3
雨蝶.ape。
找不到文件: '类似爱情.mp3
伤不起.mp3
映山红.mp3
雨蝶.ape'
未能打开 类似爱情.mp3
伤不起.mp3
映山红.mp3
雨蝶.ape。


正在退出...(End of file)
[aituroi@Ioxeemoo xin1108]$ 

:em20 原来是${f[@]}和${f[*]}的区别
学无止境呀
fnan
帖子: 919
注册时间: 2009-07-01 22:04

Re: shell数组赋值问题

#25

帖子 fnan » 2011-09-30 21:03

f=("a b" "c")
"${f[*]}" #等效 "a b c"
"${f[@]}" #等效 "a b" "c"
bash不如perl精妙,学不到lisp的皮毛,远不够c++强悍,不过可以用。
头像
vinoca
帖子: 59
注册时间: 2011-03-21 18:30

Re: shell数组赋值问题

#26

帖子 vinoca » 2011-10-02 10:40

fnan 写了:f=("a b" "c")
"${f[*]}" #等效 "a b c"
"${f[@]}" #等效 "a b" "c"
嗯,翻看了bash的参考手册,是这么说的:
If the subscript is ‘@’ or ‘*’, the word expands to all members of the array name. These subscripts differ only when the word appears within double quotes. If the word is double-quoted, ${name[*]} expands to a single word with the value of each array member separated by the first character of the IFS variable, and ${name[@]} expands each element of name to a separate word. When there are no array members, ${name[@]} expands to nothing. If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word.

有引号这俩就有区别了。
回复