每个匹配执行一次命令的通配符

时间:2017-02-03 21:50:06

标签: bash shell wildcard zsh

备用标题:如何在没有循环或xargs的情况下循环。

最近,由于其众多功能,我改用了zsh。我很好奇:是否有扩展通配符的功能,以便每次匹配执行一次命令,而不是一次只执行一次所有匹配。

实施例

命令ebook-convert input_file output_file [options]只接受一个输入文件。当我想转换多个文件时,我必须多次手动执行命令或使用循环,例如:

for i in *.epub; do 
    ebook-convert "$i" .mobi
done

我喜欢的是一个通配符,其功能类似于循环,因此我可以节省一些按键。让通配符为。命令

ebook-convert ⁂.epub .mobi

应扩展为

ebook-convert 1stMatch.epub .mobi
ebook-convert 2ndMatch.epub .mobi
ebook-convert 3rdMatch.epub .mobi
...

仍对其他答案感兴趣

我接受了一个对我有用的答案(感谢Grisha Levit)。但是如果你知道其他具有这种功能的shell,比编写循环更短的替代命令,或者甚至是一种用所需的通配符扩展zsh的方法,那么你的答案是值得赞赏的。

4 个答案:

答案 0 :(得分:4)

您可以在zsh中结帐zargs

  

此功能与GNU xargs具有类似的用途。它不是从标准输入中读取参数行,而是从命令行中获取它们

     

zshcontrib(1): OTHER FUNCTIONS, zargs

所以,我们可以写:

autoload -Uz zargs
zargs -I⁂ -- *.epub -- ebook-convert ⁂ .mobi

PS:如果您需要捕获构建命令的某些模式部分,您可以找到zmv

答案 1 :(得分:3)

  

这样我就可以保存一些按键

好的,让我们说你输入了

ebook-convert *.epub .mobi

...现在你意识到这不会起作用 - 你需要写一个循环。你通常会做什么?可能类似于:

  • ; done添加到该行的末尾
  • 点击 Ctrl A 开始行
  • 输入for i in ...
  • 等...

这看起来非常适合readline键盘宏:

让我们用readline commands和常规按键来说明这些步骤:

end-of-line                    # (start from the end for consistency)
; done                         # type in the loop closing statement
character-search-backward *    # go back to the where the glob is
shell-backward-word            # (in case the glob is in the mid-word)
shell-kill-word                # "cut" the word with the glob
"$i"                           # type the loop variable
beginning-of-line              # go back to the start of the line
for i in                       # type the beginning of the loop opening
yank                           # "paste" the word with the glob
; do                           # type the end of the loop opening

创建绑定:

对于上面使用的没有键绑定的任何readline命令,我们需要创建一个。我们还需要为我们正在创建的新宏创建一个绑定。

除非您已经完成了大量的readline自定义,否则运行以下命令将为当前shell设置绑定。这使用默认绑定,例如\C-eend-of-line

bind '"\eB": shell-backward-word'
bind '"\eD": shell-kill-word'

bind '"\C-i": "\C-e; done\e\C-]*\eB\eD \"$i\"\C-afor i in\C-y; do "'

绑定也可以进入inputrc文件以保持持久性。

使用快捷方式:

设置完毕后:

  1. 输入类似

    的内容
    ebook-convert *.epub .mobi
  2. Ctrl I
  3. 该行将转换为

    for i in *.epub; do ebook-convert "$i" .mobi; done
  4. 如果要立即运行命令,可以修改宏以附加\C-j作为最后一个按键,这将触发accept-line(与命中返回)。

答案 2 :(得分:2)

for循环有一个您可能喜欢的缩写形式:

for f (*.epub) ebook-convert $f .mobi

答案 3 :(得分:0)

你可以自己创建一个执行此操作的脚本:

#!/bin/bash

command="$1"
shift
if
  [[ $# -lt 3 ]]
then
  echo "Usage: command file/blog arg1, arg2..."
  exit 1
fi

declare -a files=()
while [ "$1" != "--" ]
do
  [ "$1" ] || continue
  files+=("$1")
  shift
done

if
  [ "$1" != "--" ]
then
  echo "Separator not found : end file list with --"
  exit 1
fi
shift

for file in "${files[@]}"
do
  "$command" "$file" "$@"
done

你这样称呼这个(假设脚本被称为apply_to)。

apply_to command /dir/* arg1, arg2...

修改

我修改了代码以在命令开头插入文件名。