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

Nar*_*ico 5 bash filenames space escaping

(用sed编写解决方案)

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

~/docs/file.*    
~/my docs/*.txt
...
Run Code Online (Sandbox Code Playgroud)

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

while read ROW
do
   rsync $ROW /my/dest/
done < list.txt
Run Code Online (Sandbox Code Playgroud)

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

rsync "$ROW" /my/dest/
Run Code Online (Sandbox Code Playgroud)

当然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
Run Code Online (Sandbox Code Playgroud)

请注意,没有引号传递给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
Run Code Online (Sandbox Code Playgroud)

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

有提示吗?谢谢.

Pat*_*uch 1

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

你能做的可以做:

ROW=$(echo $ROW | sed -e "s/ /\\\\ /g")
Run Code Online (Sandbox Code Playgroud)

或更好):

ROW=$(echo $ROW | sed -e 's/ /\\ /g')
Run Code Online (Sandbox Code Playgroud)

后一个示例使用单引号,因此 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"
Run Code Online (Sandbox Code Playgroud)

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

很抱歉一开始就错过了这一点,我只关注问题的正则表达式部分。

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

eval ls -ld $NEWROW
Run Code Online (Sandbox Code Playgroud)

或 eval rsync $NEWROW /other/path

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

//编辑:将缺失添加g到 sed 脚本中

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

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