Combinando a substituição de vários processos

6

Suponha que você tenha tentado algo assim:

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

e perceba que você deseja classificar cada arquivo (numericamente, vamos supor) antes de colar. Então, usando a substituição de processos, 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 contraventamento ou expansão de nome de caminho (curingas) que abranja a substituição de vários processos.

Existe uma ferramenta que permite escrever isso de maneira compacta (por exemplo, dando sort -n e ../data/file-{A,B,C}.dat separadamente) e compõe toda a linha de comando para você?

    
por musiphil 23.04.2013 / 08:52

2 respostas

2

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 implementações de ksh , você precisa substituir local por typeset )

Para se adaptar a qualquer comando arbitrário, (e para provar que eval pode 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
    
por 23.04.2013 / 09:13
1

Por favor, veja aqui , porque eval pode ser perigoso de usar. Como você notará, é uma ferramenta muito poderosa , mas ao mesmo tempo pode causar muito dano .

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

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

EDIT: 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 rever 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
    
por 23.04.2013 / 16:20