Combinando substituição de múltiplos processos

Combinando substituição de múltiplos processos

Suponha que você tentou algo assim:

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

e perceba que deseja classificar cada arquivo (numericamente, digamos) antes de colar. Então, usando a substituição de processo, você precisa escrever algo assim:

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

Aqui você vê muita duplicação, o que não é bom. Como cada substituição de processo é isolada uma da outra, não é possível usar nenhuma expansão de chaves ou de nome de caminho (curingas) que abranja várias substituições de processos.

Existe uma ferramenta que permite escrever isso de forma compacta (por exemplo, dando sort -ne ../data/file-{A,B,C}.datseparadamente) e compor toda a linha de comando para você?

Responder1

Você poderia fazer:

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

Ou para automatizá-lo como uma função

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

(em algumas kshimplementações, você precisa substituir localpor typeset)

Para se adaptar a qualquer comando arbitrário (e para provar que evalpode ser seguro quando usado corretamente), você poderia fazer:

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

Responder2

Por favor, vejaaqui, por que evalpode ser perigoso usar. Como você notará, é umferramenta muito poderosa, mas ao mesmo tempo podecausar muitos danos.

O script a seguir fará o que você deseja - com segurança.

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

EDITAR: O Sr. Chazelas está certo. Eu consertei minha solução, então agora você pode usar sort_ps paste file1.txt file2.txt file2.txt ... fileN.txt. Obrigado Stephane por revisar minha resposta.

Exemplo de saída:

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

informação relacionada