当变量包含斜杠(/)时,将shell变量传递给sed

时间:2015-04-02 06:33:58

标签: bash shell sed

说,文件'listall'包含目录列表,我想列出这些目录中的所有文件,包括目录路径。 我在下面写了一个bash脚本。

#!/bin/bash
\rm listZ
echo ' ' > listZ
for i in `cat listall`; ls $i | sed -e '1,$s/^/$i\//g' >> listZ; done

但是在sed命令中,$ i不会被目录名替换 我尝试使用双引号进行sed命令,但无济于事。这是在cygwin。 我该怎么办?

3 个答案:

答案 0 :(得分:1)

单引号字符串不受变量替换的影响。但是,将变量移动到外部单引号字符串是一件简单的事情,例如:

pax> one=1 ; echo '
...> 1
...> 101
...> 3.14159' | sed 's/'$one'/x/g'

x
x0x
3.x4x59

在你的情况下,它将是:

for i in `cat listall`; do ls $i | sed -e '1,$s/^/'$i'\//g' >> listZ; done
#                                                 ^^^^

请注意,根据您的评论之一,如果您的文件中包含sed特有的字符,则会让您感到悲伤。例如,如果它们包含/个字符,则您需要阻止它被sed s命令解释。

也许最简单的方法是使用另一个可能位于输入文件中的分隔符:

for i in `cat listall`; do ls $i | sed -e '1,$s?^?'$i'/?g' ; done

答案 1 :(得分:1)

DontParseLsDontReadLinesWithFor

你要问的问题可以通过使用双引号而不是单引号来修复,但是,你需要转义任何你不打算让shell解释的shell元字符(换句话说,你' d必须反斜杠 - 转义地址范围1,$中的美元符号,或使用双引号旁边的单引号,并可能更改为不同的分隔符以处理变量值$i中的斜杠; '1,$'"s:^:$i:")。

但是你的整个任务可以作为一个命令执行。

IFS=$'\n' find $(cat listall) -mindepth 1 -maxdepth 2 -print >listZ

IFS仅在listall包含带有空格的文件名时才是必需的。while read -r directory; do printf '%s\n' "$directory"/* "$directory"/*/* done <listall >listZ 您仍然原则上需要转义任何其他shell元字符(星号,方括号,问号)。

是一个更强大的解决方法
listall

(我最初误解了你的问题,假设sed "s:^:$i/:" listall >listZ 包含文件名,而不是目录名。我在下面保留原来的答案。)


'1i\ '

如果您实际上需要第一行上的空白区域(可能会将sed添加到1,$脚本中)。地址范围sed/g中的默认值,因此指定它是多余的。因为每行只能有一个替换,$i标志也是冗余的(这意味着,在一行上替换所有出现,而不是仅替换第一行)。如果{{1}}中有冒号,请使用不同的分隔符。

答案 2 :(得分:0)

正如paxdiablo所说(感谢tripleee),我的问题是shell变量包含几个&#39; /&#39;字符,搞乱了sed substitute命令。所以我们可以使用另一个分隔符来避免这个问题,例如&#39 ;;&#39;而不是&#39; /&#39;对于sed。 所以正确的方法是

#!/bin/bash
\rm listZ
echo ' ' > listZ
for i in `cat listall`; ls $i | sed 's;^;$i' >> listZ; done

注意,在我的情况下,文件listall看起来像

/usr/bin/
/usr/local/bin/