Bash - 在命令替换的结果上扩张?

时间:2016-04-21 14:12:02

标签: bash

我想在字符串中添加一个字符串到目录中的所有文件。我想做的是:

echo string{$(ls some_dir)}

这不会起作用,因为ls用空格分隔单词,而大括号扩展需要逗号。所以我想我会用tr用空格替换空格,例如:

echo string{$(ls some_dir) | tr ' ' ','}

但这不起作用,因为管道优先。

这样做的正确方法是什么?我知道我可能会使用像Python这样理智的语言,但令人沮丧的是,Bash甚至不能做那么简单的事情。

3 个答案:

答案 0 :(得分:3)

如果你真的想插入目录的内容(这是$(ls some_dir)会给你的)那么你可以做

printf 'string%s ' some_dir/*

IRL,您可能希望以换行结束。

{ printf 'string%s ' some_dir/*; echo; }

您可以将此概括为任何glob或大括号扩展的输出:

printf 'foo%d\n' {11..22}

修改

根据您的评论,您想要消除" some_dir /"另一方面,你不能只用printf做到这一点。您可以cd到目录,以便根据需要展开globs,或使用参数扩展来清理前导目录名称:

( cd some_dir && printf 'string%s ' *; echo )

{ cd some_dir && printf 'string%s ' * && cd - >/dev/null; echo; }

names=( some_dir/* ) names=( "${names[@]#some_dir/}" )
{ printf 'string%s ' "${names[@]}"; echo; }

答案 1 :(得分:0)

一种方法,它将优雅地处理文件名中的空格:

files=("$dir"/*); files=("${files[@]/#"$dir"\//"$prefix"}")

这会将前缀字符串存储在数组$files中;你可以使用数组扩展迭代它们:

for file in "${files[@]}"; do 
  # Something with file
done

或使用printf打印出来:

printf "%s\n" "${files[@]}"

使用数组扩展的优点是它不涉及分词,所以即使元素中有空格,数组扩展也会将每个元素都包含在一个单词中。

答案 2 :(得分:0)

当然,bash可以做到。

让我们一步一步来。

1。在第二个示例中解决问题

这是您的第二个示例

echo string{$(ls some_dir) | tr ' ' ','}

您将管道放在命令替换之外,这是完全错误的。

我相信您希望将流从ls输出流传输到tr输入流,因此很明显,该管道应该放在命令替换中,像这样

echo string{$(ls some_dir | tr ' ' ',')}

2。 ls的输出用换行符代替,而不是空格

所以我们开始

echo string{$(ls some_dir | tr '\n' ',')}

3。大括号扩展是在命令替换之前执行的

换句话说,将命令替换扩展到f1,f2,f3,d1,之后,将不再执行大括号扩展。

因此,毫无疑问,该命令将显示string{f1,f2,f3,d1,}

解决方案是让bash再次对其进行评估。

eval echo string{$(ls some_dir | tr '\n' ',')}

好的,到目前为止,结果看起来非常好(尝试一下,您会得到的),它非常接近您想要的东西,除了一个小地方。

您可能已经在我上面展示的输出末尾注意到了逗号。逗号导致不必要的string出现在最终输出的末尾。

让我们完成它。

4。删除结尾的逗号

eval echo string{$(echo -n "$(ls some_dir)" | tr '\n' ',')}

好的,就是这样。


哦...顺便说一句,这只是针对您特定问题的特定解决方案。您可能会开发新的问题变体,而这种特定的解决方案可能不适合您的新问题。如果是这样,我建议您运行man bash,并非常仔细地从头到脚阅读,那么您将变得势不可挡。