Combinando la sustitución de múltiples procesos

Combinando la sustitución de múltiples procesos

Supongamos que intentaste algo como esto:

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

y te das cuenta de que quieres ordenar cada archivo (numéricamente, supongamos) antes de pegarlo. Luego, usando la sustitución de procesos, debes escribir algo como esto:

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

Aquí se ve mucha duplicación, lo cual no es bueno. Debido a que cada sustitución de procesos está aislada entre sí, no puede utilizar ninguna expansión de llave o expansión de nombre de ruta (comodines) que abarque múltiples sustituciones de procesos.

¿Existe alguna herramienta que le permita escribir esto de forma compacta (por ejemplo, dando sort -ny ../data/file-{A,B,C}.datpor separado) y compone toda la línea de comando por usted?

Respuesta1

Podrías hacerlo:

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

O automatizarlo como una función.

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

(en algunas kshimplementaciones, es necesario reemplazar localcon typeset)

Para adaptarse a cualquier comando arbitrario (y demostrar que evalpuede ser seguro cuando se usa correctamente), puede hacer:

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

Respuesta2

Por favor miraaquí, por qué evalpuede ser peligroso de usar. Como notarás, es unherramienta muy poderosa, pero al mismo tiempo puedecausar mucho daño.

El siguiente script hará lo que usted quiera: de forma segura.

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

EDITAR: El Sr. Chazelas tiene razón. Arreglé mi solución, por lo que ahora puedes usarla sort_ps paste file1.txt file2.txt file2.txt ... fileN.txten su lugar. Gracias Stéphane por revisar mi respuesta.

Salida de muestra:

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

información relacionada