为每个匹配项执行一次命令的通配符
Wildcard that executes command once for each match
备用标题:如何在没有循环或 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 的方法,我们将不胜感激。
您可以在 zsh 中签出 zargs
。
This function has a similar purpose to GNU xargs. Instead of reading lines of arguments from the standard input, it takes them from the command line
所以,我们可以这样写:
autoload -Uz zargs
zargs -I⁂ -- *.epub -- ebook-convert ⁂ .mobi
PS:如果您需要捕获模式的某些部分以构建命令,您会发现 zmv
很方便。
您可以自己编写一个脚本来执行此操作:
#!/bin/bash
command=""
shift
if
[[ $# -lt 3 ]]
then
echo "Usage: command file/blog arg1, arg2..."
exit 1
fi
declare -a files=()
while [ "" != "--" ]
do
[ "" ] || continue
files+=("")
shift
done
if
[ "" != "--" ]
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...
编辑
我修改了代码以在命令开头插入文件名。
so that I can save a few keystrokes
好的,假设您输入了
ebook-convert *.epub .mobi
…现在您意识到这行不通 — 您需要编写一个循环。你通常会做什么?可能是这样的:
- 在行尾添加
; done
- 按 CtrlA 转到行首
- 输入
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
正在创建绑定:
对于上面使用的任何没有 key-binding 的 readline 命令,我们需要创建一个。我们还需要为正在创建的新宏创建绑定。
除非您已经做了很多 readline 自定义,运行使用下面的命令将为当前 shell 设置绑定。这使用默认绑定,如 \C-e
➙ end-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
文件以保持持久性。
使用快捷方式:
设置后:
输入类似
的内容
ebook-convert *.epub .mobi
- 按CtrlI
行会变换成
for i in *.epub; do ebook-convert "$i" .mobi; done
如果你想立即运行命令,你可以修改宏以附加一个\C-j
作为最后一次按键,这将触发accept-line
(与点击[相同=54=]Return).
for
循环有一个您可能喜欢的缩写形式:
for f (*.epub) ebook-convert $f .mobi
备用标题:如何在没有循环或 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 的方法,我们将不胜感激。
您可以在 zsh 中签出 zargs
。
This function has a similar purpose to GNU xargs. Instead of reading lines of arguments from the standard input, it takes them from the command line
所以,我们可以这样写:
autoload -Uz zargs
zargs -I⁂ -- *.epub -- ebook-convert ⁂ .mobi
PS:如果您需要捕获模式的某些部分以构建命令,您会发现 zmv
很方便。
您可以自己编写一个脚本来执行此操作:
#!/bin/bash
command=""
shift
if
[[ $# -lt 3 ]]
then
echo "Usage: command file/blog arg1, arg2..."
exit 1
fi
declare -a files=()
while [ "" != "--" ]
do
[ "" ] || continue
files+=("")
shift
done
if
[ "" != "--" ]
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...
编辑
我修改了代码以在命令开头插入文件名。
so that I can save a few keystrokes
好的,假设您输入了
ebook-convert *.epub .mobi
…现在您意识到这行不通 — 您需要编写一个循环。你通常会做什么?可能是这样的:
- 在行尾添加
; done
- 按 CtrlA 转到行首
- 输入
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
正在创建绑定:
对于上面使用的任何没有 key-binding 的 readline 命令,我们需要创建一个。我们还需要为正在创建的新宏创建绑定。
除非您已经做了很多 readline 自定义,运行使用下面的命令将为当前 shell 设置绑定。这使用默认绑定,如 \C-e
➙ end-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
文件以保持持久性。
使用快捷方式:
设置后:
输入类似
的内容ebook-convert *.epub .mobi
- 按CtrlI
行会变换成
for i in *.epub; do ebook-convert "$i" .mobi; done
如果你想立即运行命令,你可以修改宏以附加一个\C-j
作为最后一次按键,这将触发accept-line
(与点击[相同=54=]Return).
for
循环有一个您可能喜欢的缩写形式:
for f (*.epub) ebook-convert $f .mobi