如何替换bash的'find'找到的{}
中的字符串?
例如,我希望下面?
用“out”代替“in”:
find . -name "*.in" -exec python somescript.py {} ? \;
即。执行所有“* .in”文件
python somescript.py somefile.in somefile.out
答案 0 :(得分:2)
find
没有替换功能。你需要调用一个shell。
find . -name "*.in" -exec sh -c 'python somescript.py "$0" "${0%.in}.out"' {} \;
$0
是文件名,${0%.in}
删除.in
后缀。
或者,在bash中(但不是普通的),运行shopt -s globstar
以启用递归目录扩展(以及shopt -s nullglob
如果存在无法匹配的风险.in
文件)并使用for
循环代替find
。
for x in **/*.in; do
python somescript.py "$x" "${x%.in}.out"
done
答案 1 :(得分:0)
使用bash -c
命令使用find
命令:
find -name "*.in" -exec bash -c 'python somescript.py "$1" "$(dirname "$1")/$(basename "$1" .in).out"' _ {} \;
找到的文件名{}
被bash
视为$1
争论。
命令basename
删除扩展名,dirname
保留路径名。
答案 2 :(得分:0)
find . -name "*.in" -exec bash -c 'python script.py "${0%.*}"{.in,.out}' {} \;
find . -name "*.in" -exec bash -c 'python script.py "${0} ${0/.in/.out}"' {} \;
<强>结果强>:
python script.py somefile.in somefile.out
答案 3 :(得分:0)
对我来说,所有内置工具都使用起来有点麻烦(我是否正确引用了shell脚本?它会做正确的事情吗?我可以轻松预览更改吗?)。
几年前,我写了rpt,它将使用其命令行参数,打开一个文本编辑器(让您编辑文件名),然后在其上运行命令(默认为mv
)旧文件名和新文件名。
最近,我进一步走了一步,这里是fea
(针对每个参数):
#!/usr/bin/env python3
# fea: For Each Argument
# https://thp.io/2019/rpt-and-fea.html
import sys, shlex, re
_, cmd, *args = sys.argv
print('\n'.join(re.sub(r'[{](.)([^}]*?)(\1)([^}]*?)(\1)[}]',
lambda m: shlex.quote(re.sub(m.group(2), m.group(4), arg)),
cmd).replace('{}', shlex.quote(arg)) for arg in args))
发生以下替换:
{} -> insert arg
{/regex/replacement/} -> run re.sub(regex, replacement) on the arg,
you can pick any character for "/", as long
as it appears at the start, middle and end
(to separate the regex from the replacement)
一些用例:
# Create backup files
fea "cp {} {}.bak" *.py
# Encode WAV files with oggenc
fea "oggenc {} -o {/wav$/ogg/}" *.wav
# Decode MP3 files with mpg123
fea "mpg123 -w {/mp3$/wav/} {}" *.mp3
# Render markdown documents to HTML
fea "markdown {} > {/md$/html/}" *.md
# Fancy replacement
fea "markdown {} > {#input/(.*).md#output/\1.html#}" input/*.md
# As mentioned above, note that you need to pipe the
# fea output into a shell to execute the command
fea "cp {} {}.bak" *.py | sh -e -x
您的用例可以这样覆盖:
find . -name '*.in' -print0 | xargs -0 fea "python somescript.py {} {/in$/out/}"
或者如果文件仅在当前文件夹中:
fea "python somescript.py {} {/in$/out/}" *.in
或者如果您将zsh
与recursive globbing一起使用:
fea "python somescript.py {} {/in$/out/}" **/*.in
如果您对显示的命令感到满意,只需将其输出通过管道输送到sh -e -x
(或bash
或其他任何设备)中即可执行。
虽然可以使用外壳程序(或任何参数/变量扩展名)进行for
循环,但是外壳程序引号和转义很难(对我而言)正确使用,fea
工具确保它也可以使用奇怪的名称:
touch 'some$weird "filename.py'
touch 'and !! more.py'
touch 'why oh why?.py'
touch "this is ridiculous'.py"
fea "cp {} {}.bak" *.py | sh -e -x
有关详细信息,请参见rpt and fea blog post。
答案 4 :(得分:0)
或者,只需修改somescript.py
来创建输出文件名(在Python中比在shell中做起来容易,因为没有特殊的字符可能会以某种方式解释):
find . -name '*.in' -exec python somescript.py {} .out \;
以脚本开头:
import sys, os
inputfilename = sys.argv[1]
outputfilename = os.path.splitext(inputfilename)[0] + sys.argv[2]
# ...
当然,您也可以对.out
进行硬编码并删除该参数。
如果由于某种原因无法修改somescript.py,则可以轻松创建一个包装脚本,以正确的方式调用somescript.py
。