Предварительный текст к каждому аргументу подстановочного знака в bash

Простой пример: mybin *.txt будет расширяться до mybin a.txt b.txt c.txt

Но я ищу простое решение для расширения что-то вроде: mybin --conf a.txt --conf b.txt --conf c.txt,

Есть ли встроенный в это? Какой самый простой способ для этого?

5 ответов

Решение

find мой друг:

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

Немного хитрое решение:

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

Для всех текстовых файлов

eval mybin "$(printf -- '--conf %q ' *.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

Создайте несколько текстовых файлов, некоторые имена файлов содержат пробелы или специальные символы

touch {a,b,c,d,efg,"h h"}.txt 'a(1).txt' 'b;b.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

для определенных текстовых файлов:

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
# 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, а не только 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}
set -- *.txt

for thing do
    shift
    set -- "$@" --conf "$thing"
done

mybin "$@"

Это будет использовать список позиционных параметров ($@), чтобы держать расширенный шаблон шара. Затем мы перебираем эти элементы и модифицируем $@ вставив --conf перед каждым. mybin утилита может быть вызвана с этим списком.

Цитирование в коде является намеренным, чтобы не дать оболочке разбить любые строки на пробелах и развернуть любые глобусы имен файлов, если они встречаются как надлежащие части имен файлов, которые *.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[@]}"

В качестве функции оболочки:

delim_run () {
    cmd=$1
    delim=$2

    shift 2

    for thing do
        shift
        set -- "$@" "$delim" "$thing"
    done

    "$cmd" "$@"
}

Тогда вы сможете сделать

delim_run mybin --conf *.txt
Другие вопросы по тегам