Bash:在扩展后包含变量的表达式中丢失引号

时间:2015-07-15 17:11:50

标签: bash

我刚开始学习Bash脚本并写了一些东西:

#!bin/bash
for str in stra strb strc
do
find . -name "*${str}*" | sort | cut -c3- > "${str}.list"
done

正如您所看到的,我正在尝试创建三个文件(“stra.list”,“strb.list”和“strc.list”),这些文件将列出包含“stra”,“strb”的文件的名称“,或”strc“分别在当前目录中。 cut -c3- hack仅用于在查找结果的开头删除路径名./

但我现在所有的脚本都在创建三个空文件......

所以当我跑

for str in stra strb strc;
do
echo "find .-name "*${str}*" | sort | cut -c3- > "${str}.list"";
done

我只看到

find .-name *stra* | sort | cut -c3- > stra.list
find .-name *strb* | sort | cut -c3- > strb.list
find .-name *strc* | sort | cut -c3- > strc.list

那么如何在扩展后保留包含变量的表达式周围的引号?我尝试添加一组额外的引号以及使用eval,但似乎都不起作用。

更新: 我要问的是我如何编写我的find命令,以便Bash能够成功生成带有目标文件名的三个列表,而不是出于任何原因只创建三个空白列表。对此感到抱歉。

2 个答案:

答案 0 :(得分:1)

如果您的目标是生成有效的shell命令,那么只是尝试保留引号是错误的(从某种意义上说它实际上是不安全的;恶意生成的变量内容可以执行shell注入攻击)。相反,告诉shell本身为要保留的内容生成有效的引用; printf %q将在bash中执行此操作。

此特定变体需要足够新的bash才能拥有printf -v

#!/bin/bash
for str in stra strb strc; do
  printf -v start '%q ' find . -name "*${str}*"
  printf -v end '%q ' "${str}.list"
  printf '%s\n' "$start | sort | cut -c3- >$end"
done

相比之下,如果您只是想修复原始脚本中的错误,假设您有GNU find

#!/bin/bash
for str in stra strb strc; do
  find . -maxdepth 1 -name "*${str}*" -printf '%P\n' | sort > "${str}.list"
done

find操作-printf '%P\n'打印没有起始目录的名称,这意味着不需要删除./

因为你说你只是在当前目录中寻找文件,顺便说一下,这整个混乱都是过度的。你根本不需要find

for str in stra strb strc; do
  files=( *"$str"* )
  [[ -e $files ]] && printf '%s\n' "${files[@]}" >"$str.list"
done

请注意,如果您的任何文件名包含文字换行符,则此命令的输出可能会产生误导。 (出于这个原因,将文件名存储在换行符分隔的文件中是个坏主意)。

答案 1 :(得分:0)

有两种方法:

  1. 用单引号而不是双引号括起你的echo输出:

    echo 'find .-name "*${str}*" | sort | cut -c3- > "${str}.list"';  
    
  2. 或在内部引号前添加\(反斜杠):

    echo "find .-name \"*${str}*\" | sort | cut -c3- > \"${str}.list\"";