Kombinieren mehrerer Prozesssubstitutionen

Kombinieren mehrerer Prozesssubstitutionen

Angenommen, Sie hätten Folgendes versucht:

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

und stellen Sie fest, dass Sie jede Datei (nehmen wir an, numerisch) vor dem Einfügen sortieren möchten. Dann müssen Sie mithilfe der Prozesssubstitution etwas wie das Folgende schreiben:

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

Hier sehen Sie viele Duplikate, was nicht gut ist. Da jede Prozessersetzung von den anderen isoliert ist, können Sie keine Klammern oder Pfadnamenerweiterungen (Platzhalter) verwenden, die mehrere Prozessersetzungen umfassen.

Gibt es ein Tool, mit dem Sie dies kompakt schreiben können (z. B. indem Sie sort -nund ../data/file-{A,B,C}.datgetrennt angeben) und das die gesamte Befehlszeile für Sie zusammenstellt?

Antwort1

Du könntest es tun:

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

Oder es als Funktion zu automatisieren

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

(in einigen kshImplementierungen müssen Sie localdurch ersetzen typeset)

Zur Anpassung an beliebige Befehle (und um zu beweisen, dass sie evalbei ordnungsgemäßer Verwendung sicher sein können) können Sie Folgendes tun:

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

Antwort2

Bitte beachten SieHier, warum evalkann gefährlich sein, zu verwenden. Wie Sie feststellen werden, ist es einsehr leistungsstarkes Werkzeug, kann aber gleichzeitigviel Schaden anrichten.

Das folgende Skript erledigt das Gewünschte – und zwar sicher.

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

EDIT: Herr Chazelas hat Recht. Ich habe meine Lösung korrigiert, sodass Sie jetzt sort_ps paste file1.txt file2.txt file2.txt ... fileN.txtstattdessen verwenden können. Vielen Dank, Stephane, für die Überprüfung meiner Antwort.

Beispielausgabe:

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

verwandte Informationen