我试图编写一个 shell 脚本来复制文件。以下是我所做的。
workingDirectory=$(pwd | sed "s/ /\\ /g")
现在echo $workingDirectory
显示/home/user/Documents/Learning and Development/
。
但我知道,为了让cp
命令正常工作,我需要用\
(反斜杠+空格)替换空格。所以我sed
稍微修改了命令,如下:
workingDirectory=$(pwd | sed "s/ /\\\ /g")
如此看来,echo $workingDirectory
一切/home/user/Documents/Learning\ and\ Development/
都很好。
但是当尝试使用cp
命令时,
cp $workingDirectory/jad/jad /usr/bin/
我收到错误,
cp: cannot stat ‘/home/user/Documents/Learning\\’: No such file or directory
cp: cannot stat ‘and\\’: No such file or directory
cp: cannot stat ‘Development/jad/jad’: No such file or directory
这可能是什么原因?如何解决?
编辑
如果我使用第一个sed
命令,那么错误是
cp: cannot stat ‘/home/user/Documents/Learning’: No such file or directory
cp: cannot stat ‘and’: No such file or directory
cp: cannot stat ‘Development/jad/jad’: No such file or directory
答案1
转义变量内的字段分隔符来防止单词拆分是没有用的:shell 仍然会根据列出的分隔符拆分单词$IFS
:
~/tmp/directory with spaces$ workingDirectory=$(pwd | sed "s/ /\\\ /g")
~/tmp/directory with spaces$ echo $workingDirectory
/home/user/tmp/directory\ with\ spaces
~/tmp/directory with spaces$ strace /bin/echo $workingDirectory |& grep '^execve'
execve("/bin/echo", ["/bin/echo", "/home/user/tmp/directory\\", "with\\", "spaces"], [/* 62 vars */]) = 0
因此,一个明显的解决方法是将其设置$IFS
为空字符串(并完全避免转义空格),从本质上完全禁用单词拆分:
~/tmp/directory with spaces$ workingDirectory=$(pwd)
~/tmp/directory with spaces$ echo $workingDirectory
/home/user/tmp/directory with spaces
~/tmp/directory with spaces$ IFS=
~/tmp/directory with spaces$ strace -s 64 /bin/echo $workingDirectory |& grep '^execve'
execve("/bin/echo", ["/bin/echo", "/home/user/tmp/directory with spaces"], [/* 62 vars */]) = 0
~/tmp/directory with spaces$ stat $workingDirectory
File: ‘/home/user/tmp/directory with spaces’
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 812h/2066d Inode: 782086 Links: 2
Access: (0775/drwxrwxr-x) Uid: ( 1000/ user) Gid: ( 1000/ user)
Access: 2016-03-24 11:22:43.606332994 +0100
Modify: 2016-03-24 10:51:00.835689309 +0100
Change: 2016-03-24 10:51:00.835689309 +0100
Birth: -
但是,完全禁用分词功能一般来说意义不大。除非您有充分的理由完全禁用多个命令的分词功能,否则我建议您仅使用双引号将其限制在可能包含字段分隔符的字符串中:
workingDirectory=$(pwd)
cp "$workingDirectory"/jad/jad /usr/bin/