如何在“find(...) - exec(...){} \;”中替换{}中的字符串bash命令?

时间:2018-05-18 08:09:00

标签: bash find

如何替换bash的'find'找到的{}中的字符串?

例如,我希望下面?用“out”代替“in”:

find . -name "*.in" -exec python somescript.py {} ? \;

即。执行所有“* .in”文件

python somescript.py somefile.in somefile.out

5 个答案:

答案 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)

使用Brace Expansion

find . -name "*.in" -exec bash -c 'python script.py "${0%.*}"{.in,.out}' {} \;

使用Shell Parameter Expansion

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

或者如果您将zshrecursive 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