5

(使用 sed 编辑解决方案)

我有一个文件名和目录列表,包括波浪号和通配符。例如:

~/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。文件“~/abc/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 ,因此通配符不会扩展,但空格会不断破坏文件名,尽管已转义。

任何提示?谢谢。

4

2 回答 2

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

这应该也能正常工作,而不会影响启动子shell 的性能。

//编辑:添加缺少g到 sed 脚本

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

//编辑:添加评估解决方案

于 2011-01-18T10:27:19.173 回答
0

我认为您可以将要 rsync 的列表通过管道传输到单独的文件中,然后执行它,例如

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

sh rsync.txt
于 2011-01-18T10:37:35.133 回答