Объединение нескольких замещений процессов

Объединение нескольких замещений процессов

Предположим, вы попробовали что-то вроде этого:

$ paste ../data/file-{A,B,C}.dat

и понимаете, что вы хотите отсортировать каждый файл (предположим, по номерам) перед вставкой. Затем, используя подстановку процессов, вам нужно написать что-то вроде этого:

$ paste <(sort -n ../data/file-A.dat) \
        <(sort -n ../data/file-B.dat) \
        <(sort -n ../data/file-C.dat)

Здесь вы видите много дублирования, что не есть хорошо. Поскольку каждая подстановка процесса изолирована от другой, вы не можете использовать никакое расширение скобок или расширение имени пути (подстановочные знаки), которое охватывает несколько подстановок процесса.

Есть ли инструмент, который позволяет записать это компактно (например, указав sort -nи ../data/file-{A,B,C}.datотдельно) и составляет для вас всю командную строку?

решение1

Вы можете сделать:

eval paste '<(sort -n ../data/file-'{A,B,C}'.dat)'

Или автоматизировать это как функцию

sort_paste() {
  local n i cmd
  n=1 cmd=paste
  for i do
    cmd="$cmd <(sort -n -- \"\${$n}\")"
    n=$(($n + 1))
  done
  eval "$cmd"
}
sort_paste  ../data/file-{A,B,C}.dat

(в некоторых kshреализациях необходимо заменить localна typeset)

Чтобы приспособиться к любой произвольной команде (и доказать, что она evalможет быть безопасной при правильном использовании), вы можете сделать следующее:

xproc() {
  local n i cmd stage stage1 stage2 stage3
  cmd= xcmd= stage=1 n=1
  stage1='cmd="$cmd \"\${$n}\""'
  stage2='xcmd="$xcmd \"\${$n}\""'
  stage3='cmd="$cmd <($xcmd \"\${$n}\")"'
  for i do
    if [ -z "$i" ] && [ "$stage" -le 3 ]; then
      stage=$(($stage + 1))
    else
      eval 'eval "$stage'"$stage\""
    fi
    n=$(($n + 1))
  done
  eval "$cmd"
}

xproc paste '' sort -n -- '' ../data/file-{A,B,C}/dat

решение2

Пожалуйста, посмотриздесь, почему evalможет быть опасно использовать. Как вы заметите, этоочень мощный инструмент, но в то же время можетпричинить большой ущерб.

Следующий скрипт сделает то, что вам нужно, причем безопасно.

sort_ps () 
{ 
    local cmd="$1" p=()
    shift;
    for f in "$@"; do
        p+=(<(sort -n "$f"));
    done
    "$cmd" "${p[@]}"
}

EDIT: Г-н Шазелас прав. Я исправил свое решение, так что теперь вы можете использовать sort_ps paste file1.txt file2.txt file2.txt ... fileN.txtего. Спасибо, Стефан, за просмотр моего ответа.

Пример вывода:

rany$ sort_ps sprunge foo1.txt foo.txt 
http://sprunge.us/EBZf?/dev/fd/62
http://sprunge.us/TQGC?/dev/fd/62

Связанный контент