是否可以提前强制zsh参数扩展?

是否可以提前强制zsh参数扩展?,zsh,Zsh,问题:我目前在zsh脚本中有一个这种结构的管道 a|b|c|d|e >result 我想对此进行修改,以便如果某个变量$v不是空的,那么文件result应该只包含那些与$v中的regexp匹配的行。以下是三种显而易见的方法: # I don't like this because it causes an extra (possibly large) # temporary file a|b|c|d|e >result if [[ -n $v ]] then mv result

问题:我目前在zsh脚本中有一个这种结构的管道

a|b|c|d|e >result
我想对此进行修改,以便如果某个变量$v不是空的,那么文件
result
应该只包含那些与$v中的regexp匹配的行。以下是三种显而易见的方法:

# I don't like this because it causes an extra (possibly large)
# temporary file
a|b|c|d|e >result
if [[ -n $v ]]
then
  mv result result1
  grep -E $v result1 >result
  rm result1
fi

或:

我真正想要的是:

# This does not work
if [[ -z $v ]]
then
  filter=
else
  filter='|grep -E $v'
fi
a|b|c|d|e ${(z)filter} >result
这不起作用,因为Zsh首先识别各个命令,然后计算参数,因此将我的filter命令作为参数传递给程序e

我知道我也可以通过基于$v的值构建命令行,然后使用
eval
来解决这个问题,但我也不喜欢这样,因为在实际情况下,所有涉及的程序都会获得多个参数,并进行大量引用,而将其置于一种在评估时仍然有效的形式也很容易导致错误


在生成命令之前,是否有其他方法强制对$filter进行求值?我使用的是Zsh 5.3。

解决方案可能是使用fifo和文件描述符,比如

# open fd 3
if [[ -z $v ]]; then
    exec 3> result
else
    fifo=/tmp/fifo$$
    mkfifo "$fifo"
    grep -E "$v" "$fifo" >result & grep_pid=$!
    exec 3>"$fifo"
end

a|b|c|d|e >&3

# close fd3 and clean
exec 3>&-
if [[ -n $v ]]; then
    wait $grep_pid
    rm "$fifo"
fi
您只需将管道插入
if
语句即可。您可以复制
e

a | b | c | d | e |
  if [[ -z $v ]]; then
    e
  else
    e | grep -F $v
  fi > result
或者,如果需要额外的
cat
命令将输出通过管道,则将
e
拉出
(如果
):

a | b | c | d | e |
  if [[ -z $v ]]; then
    cat
  else
    grep -F $v
  fi > result
或者,您可以使用参数扩展来定义“接受任何东西”模式,以便与
grep
一起使用

a | b | c | d | e | grep -F ${v:-.} > result

有时
grep-E
有时
grep-F
这是一个打字错误,还有另一个解决方案,但总是运行grep:
grep-E“${v:-^}”
a | b | c | d | e |
  if [[ -z $v ]]; then
    cat
  else
    grep -F $v
  fi > result
a | b | c | d | e | grep -F ${v:-.} > result