Bash逃脱了波浪线和通配符,但没有空间

时间:2011-01-18 10:10:33

标签: bash escaping filenames space

(用sed在溶液中编辑)

我有一个文件名和目录列表,包括代字号和通配符。 E.g:

~/docs/file.*    
~/my docs/*.txt
...

我读取行并将它们传递给命令(例如rsync):

while read ROW
do
   rsync $ROW /my/dest/
done < list.txt

问题是处理文件名中的空格。如果我把$ ROW放在像这样的双引号中

rsync "$ROW" /my/dest/

当然bash不会逃脱通配符和波浪号。但是,如果我不使用引号,则空格会破坏行。

一种可能的解决方案是改变IFS(小心:脚本比我报告的更复杂)。 另一个解决方案(感谢Patrick Echterbruch的解决方案)是预先逃离空间。但是,以下代码对我不起作用:

while read ROW
do
    export NEWROW=$(echo $ROW | sed -e 's/ /\\ /g') 
    echo "Value: $NEWROW"
    ls -1d $NEWROW
done < list.txt

请注意,没有报价传递给ls。文件“〜/ a b c / test.txt”存在,但我得到:

Value: ~/saver/a\ b\ c/*.txt
ls: impossibile accedere a ~/saver/a\: Nessun file o directory
ls: impossibile accedere a b\: Nessun file o directory
ls: impossibile accedere a c/*.txt: Nessun file o directory

似乎NEWROW作为字符串传递给ls,因此通配符不会被扩展,但空格不会破坏文件名,但会被转义。

任何提示? 感谢。

2 个答案:

答案 0 :(得分:1)

据我所知,您发布的sed脚本不会产生任何影响 - “搜索”和“替换”部分是相同的。

你能做什么:

ROW=$(echo $ROW | sed -e "s/ /\\\\ /g")

或(更好):

ROW=$(echo $ROW | sed -e 's/ /\\ /g')

后一个示例使用单引号,因此shell不会特别处理反斜杠。

关于出现的第二个问题:当在程序的参数中遇到特殊字符(如~)时,它们会被bash扩展。将它们存储在变量中时,它们不会被展开,也不会在将变量作为参数传递给命令时bash检查和扩展变量的内容。

这就是为什么rsync $NEWROW ...不起作用的原因 - rsync接收$ NEWROW的未修改内容作为第一个参数,然后必须自己进行类似shell的扩展。

我所知道的唯一解决方法是在子shell中运行命令,即:

ROW="~/a b c"
$NEWROW=$(echo $ROW | sed -e 's/ /\\ /g')
bash -c "ls -ld $f"

这将导致当前运行的bash提取变量内容(即~/a\ b\ c并将其传递给它将要调用的第二个shell。这个“内部”bash将接收命令以及参数和意志然后当然是参数扩展。

很抱歉在开始时忽略了这一点,我只关注问题的正则表达式部分。

找到另一种可能的解决方案:使用sed转换路径后(例如NEWROW=$(echo $ROW | sed -e 's/ /\\ /g')尝试:

eval ls -ld $NEWROW

或     eval rsync $ NEWROW / other / path

这也应该起作用,没有启动子壳的性能影响。

//编辑:在sed脚本中添加了缺失的g

//编辑:添加了路径名扩展问题的解决方法

//编辑:Addes eval解决方案

答案 1 :(得分:0)

我认为您可以将列表作为rsync传递到单独的文件中,并执行它,如

while read ROW
do
  echo "rsync '$ROW' /my/dest/"
done < list.txt > rsync.txt

sh rsync.txt