【问题标题】:Prepending some text to each "wildcard" argument in bash在 bash 中为每个“通配符”参数添加一些文本
【发布时间】:2018-09-27 06:23:14
【问题描述】:

一个简单的例子:mybin *.txt 将扩展为mybin a.txt b.txt c.txt

但我正在寻找一个简单的解决方案来扩展为:mybin --conf a.txt --conf b.txt --conf c.txt

有内置的功能吗?最简单的方法是什么?

【问题讨论】:

  • 我不知道是否有一种简单的方法可以做到这一点,但如果你需要的不仅仅是一个配置文件,我会跟随操作系统的领导......例如,apt 有它的apt.conf.d 文件夹,以及许多其他程序
  • sed 's/\(^.*$\)/--conf \1/g' < <(ls -1 *.txt)(这里是ls -one...)您可以简单地使用printf "%s " 删除新行,例如printf "%s " $(sed 's/\(^.*$\)/--conf \1/g' < <(ls -1 *.txt))
  • mybin 是否能够从stdin 读取配置?
  • 如果是这样,我认为你可以这样做cat *.txt | mybin --conf -,这比使用eval更安全

标签: bash wildcard wildcard-expansion


【解决方案1】:

find是我的朋友:

mybin $(find /wherever/ -name '*.txt' -printf '--conf %p ')

【讨论】:

  • 如果文件名包含空格或特殊字符...eval mybin "$(find ./ -name '*.txt' -printf '--conf "%p" ')"
【解决方案2】:

有点棘手的解决方案:

eval mybin "--conf\ {`echo *.txt|tr -s " " ,`}"

【讨论】:

    【解决方案3】:

    对于所有 txt 文件

    eval mybin "$(printf -- '--conf %q ' *.txt)"
    

    如果只针对某些 txt 文件

    eval mybin '--conf "'{a,b,c}.txt'"'
    

    也许我们应该使用包装函数。这不是内置解决方案,但如果文件名包含空格或特殊字符,它比前两个命令效果更好。

    函数mybinw:

    function mybinw() {
      declare -a mybin_opts
    
      for file in "$@"; do
        mybin_opts+=(--conf "$file")
      done
    
      mybin "${mybin_opts[@]}"
    }
    

    测试:

    mybin:

    #!/bin/bash
    
    for q in "$@"; do
      echo "=> $q"
    done
    

    创建一些txt文件,一些文件名包含空格或特殊字符

    touch {a,b,c,d,efg,"h h"}.txt 'a(1).txt' 'b;b.txt'
    

    对于所有 txt 文件:

    eval mybin "$(printf -- '--conf %q ' *.txt)"
    
    => --conf
    => a(1).txt
    => --conf
    => a.txt
    => --conf
    => b;b.txt
    => --conf
    => b.txt
    => --conf
    => c.txt
    => --conf
    => d.txt
    => --conf
    => efg.txt
    => --conf
    => h h.txt
    

    对于某些 txt 文件:

    eval mybin '--conf "'{a,b,c,"h h"}.txt'"'
    
    => --conf
    => a.txt
    => --conf
    => b.txt
    => --conf
    => c.txt
    => --conf
    => h h.txt
    

    使用包装函数

    touch 'c"c.txt'
    
    mybinw *.txt
    
    => --conf
    => a(1).txt
    => --conf
    => a"b.txt
    => --conf
    => a.txt
    => --conf
    => b;b.txt
    => --conf
    => b.txt
    => --conf
    => c"c.txt
    => --conf
    => c.txt
    => --conf
    => d.txt
    => --conf
    => efg.txt
    => --conf
    => h h.txt
    

    【讨论】:

    • 试试'a"b.txt'
    • @mosvy 啊,是的。实际上,这个问题并没有一个完美的答案。
    • 对于eval解决方案,您可以使用%q来保护特殊字符:eval "mybin$(printf ' --conf %q' *.txt)"
    • @PesaThe 非常感谢!我在您的帮助下更新了我的答案。
    【解决方案4】:
    # usage mix command switch args ...
    mix(){
            p=$1; shift; q=$1; shift; c=
            i=1; for a; do c="$c $q \"\${$i}\""; i=$((i+1)); done
            eval "$p $c"
    }
    
    mix mybin --conf *.txt
    

    这可以移植到任何 POSIX shell,而不仅仅是bash,并且能够处理带有空格、特殊字符等的文件名:

    $ qecho(){ for a; do echo "{$a}"; done; }
    $ touch 'a;b' "a'b" "a\\'b" 'a"b' 'a\"b' '(a b)' '(a    b)' 'a
    b'
    $ mix qecho --conf *
    {--conf}
    {(a    b)}
    {--conf}
    {(a b)}
    {--conf}
    {a
    b}
    {--conf}
    {a"b}
    {--conf}
    {a'b}
    {--conf}
    {a;b}
    {--conf}
    {a\"b}
    {--conf}
    {a\'b}
    

    【讨论】:

      【解决方案5】:
      set -- *.txt
      
      for thing do
          shift
          set -- "$@" --conf "$thing"
      done
      
      mybin "$@"
      

      这将使用位置参数列表 ($@) 来保存扩展的 glob 模式。然后我们遍历这些项目并通过在每个项目之前插入--conf 来修改$@。然后可以使用此列表调用 mybin 实用程序。

      代码中的引用旨在阻止 shell 拆分空格上的任何字符串以及扩展任何文件名 glob(如果它们作为 *.txt 匹配的文件名的适当部分出现)。

      bash 特定的变体:

      files=( *.txt )
      
      for thing in "${files[@]}"; do
          args+=( --conf "$thing" )
      done
      
      mybin "${args[@]}"
      

      上述两者的较短变体。先发给/bin/sh

      set --
      for thing in *.txt; do
          set -- "$@" --conf "$thing"
      done
      
      mybin "$@"
      

      那么对于bash

      for thing in *.txt; do
          args+=( --conf "$thing" )
      done
      
      mybin "${args[@]}"
      

      作为一个shell函数:

      delim_run () {
          cmd=$1
          delim=$2
      
          shift 2
      
          for thing do
              shift
              set -- "$@" "$delim" "$thing"
          done
      
          "$cmd" "$@"
      }
      

      然后你就可以做

      delim_run mybin --conf *.txt
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-13
        • 2013-11-18
        • 2016-02-03
        • 1970-01-01
        • 2017-11-28
        • 1970-01-01
        • 2011-02-21
        相关资源
        最近更新 更多