我正在尝试在另一个命令中使用两个变量。例如,
Range
这不起作用。当我将全部内容写在一行中时,它就可以工作。
编辑: 我想grep两个文件列表,然后仅打印常见文件列表。但是我仍然希望变量在那里,因为它们在下面的多个地方使用。
答案 0 :(得分:3)
Bash变量是字符串,而不是延迟求值的表达式。如果您希望以后可以进行评估,请使用函数。
var1() { ls | grep "foo"; }
var2() { ls | grep "bar"; }
common=$(comm -1 -2 <(var1) <(var2))
您可以重构:
lsgrep() { ls | grep "$1"; }
common=$(comm -1 -2 <(lsgrep foo) <(lsgrep bar)
答案 1 :(得分:2)
忽略解析ls
并将命令存储在变量中的问题,您希望在两个变量中使用实际的命令而不是命令的结果。
var1='ls | grep foo'
var2='ls | grep bar'
common=$(comm -1 -2 <($var1) <($var))
让我们先摆脱变量。使用函数存储代码。
g1 () { ls | grep foo; }
g2 () { ls | grep bar; }
common=$( comm -1 -2 <(g1) <(g2) )
现在,让我们摆脱ls
,尽管这并不能真正解决解析ls
的输出所带来的实际问题,即无法将包含换行符的单个文件名与两个文件名区分开单独的文件名。
g1 () { printf '%s\n' *foo*; }
g2 () { printf '%s\n' *bar*; }
common=$( comm -1 -2 <(g1) <(g2) )
答案 2 :(得分:1)
<(cmd)
从cmd
的输出创建一个匿名文件。除非您的变量包含命令(对此不满意),否则您应编写<(printf %s "$var")
来创建具有$var
内容的匿名文件。
var1=$(ls | grep "foo")
var2=$(ls | grep "bar")
common=$(comm -1 -2 <(printf %s "$var1") <(printf %s "$var2"))
也不要解析ls
的输出。使用find
或遍历。就您而言,您可以将整个脚本替换为
printf '%s\n' * | grep foo | grep bar
甚至
printf '%s\n' *foo*bar* *bar*foo*
答案 3 :(得分:0)
鉴于您shouldn't parse the output ls通常被接受,并且您正在使用bash,因此建议您使用globlob和数组。也许是这样的:
$ touch foobar foo_and_bar bar_foo foo_alone just_bar
$ declare -A a b
$ for f in *foo*; do a["$f"]=1; done
$ for f in *bar*; do unset a["$f"]; done
$ declare -p a
declare -A a=([foo_alone]="1" )
或
$ printf '%q\n' "${!a[@]}"
foo_alone
这使用关联数组(要求bash版本4或更高版本)将第一组中的文件名存储为索引值。然后,它逐步浏览第二组,删除匹配的文件,显然会留下所有不匹配的文件。
它的输出不是完整的差异,这是您从comm -23
获得的东西,但是它以bash本地处理比较,而不是生成外部程序。您可以交换glob以对其进行调整,以使此功能类似于comm -12
。 (但是foo
和bar
只是占位符。)
答案 4 :(得分:-1)
原始版本的最小修改如下:
var1='ls|grep foo'
var2='ls|grep bar'
common=$(comm -1 -2 <(eval $var1) <(eval $var2))
关键是使用eval
并推迟对var的评估。