Tách một đầu vào cho các lệnh khác nhau và kết hợp kết quả


8

Tôi biết cách kết hợp các kết quả của lệnh khác nhau

paste -t',' <(commanda) <(commandb)

Tôi biết đường ống đầu vào giống nhau cho lệnh khác nhau

cat myfile | tee >(commanda) >(commandb)

Bây giờ làm thế nào để kết hợp các lệnh này? Để tôi có thể làm

cat myfile | tee >(commanda) >(commandb) | paste -t',' resulta resultb

Nói rằng tôi có một tập tin

tập tin của tôi:

1
2
3
4

Tôi muốn tạo một tập tin mới

1 4 2
2 3 4
3 2 6
4 1 8

Tôi đã sử dụng

cat myfile | tee >(tac) >(awk '{print $1*2}') | paste

sẽ cho tôi kết quả theo chiều dọc, nơi tôi thực sự muốn dán chúng theo thứ tự ngang.


bạn có thể phải viết hai luồng để tách các ống tên và kết hợp chúng với một chương trình giám sát.
友情 留 6/2/2015

Câu trả lời:


8

Khi bạn phát hiện ra nhiều sự thay thế quy trình, bạn không được đảm bảo có được đầu ra theo bất kỳ thứ tự cụ thể nào, vì vậy bạn nên gắn bó với

paste -t',' <(commanda < file) <(commandb < file)

Giả sử cat myfilelà viết tắt của một số đường ống đắt tiền, tôi nghĩ bạn sẽ phải lưu trữ đầu ra, trong một tệp hoặc một biến:

output=$( some expensive pipeline )
paste -t',' <(commanda <<< "$output") <(commandb <<< "$output")

Sử dụng ví dụ của bạn:

output=$( seq 4 )
paste -d' ' <(cat <<<"$output") <(tac <<<"$output") <(awk '$1*=2' <<<"$output")
1 4 2
2 3 4
3 2 6
4 1 8

Một suy nghĩ khác: FIFO và một đường ống dẫn duy nhất

mkfifo resulta resultb
seq 4 | tee  >(tac > resulta) >(awk '$1*=2' > resultb) | paste -d ' ' - resulta resultb
rm resulta resultb
1 4 2
2 3 4
3 2 6
4 1 8

Tôi có thể sử dụng sth like / dev / fd / 3-9 không?
user40129 6/2/2015

4

Các yashvỏ có nhiều tính năng độc đáo ( đường ống chuyển hướngquá trình chuyển hướng ) mà làm cho điều đó dễ dàng hơn đó:

cat myfile | (
  exec 3>>|4
  tee /dev/fd/5 5>(commanda >&3 3>&-) 3>&- |
    commandb 3>&- |
    paste -d , /dev/fd/4 - 3>&-
)

3>>|4( chuyển hướng đường ống ) tạo ra một đường ống trong đó đầu viết nằm trên fd 3 và đầu đọc trên fd 4.

3>(commanda>&3)chuyển hướng quá trình , hơi giống như thay thế quá trình ksh / zsh / bash nhưng chỉ thực hiện chuyển hướng và không thay thế bằng /dev/fd/n. kshCủa >(cmd)ít nhiều giống như yashcủa n>(cmd) /dev/fd/n(có nmột bộ mô tả tệp được chọn kshmà bạn không có quyền kiểm soát).


3

Với zsh:

pee() (
  n=0 close_in= close_out= inputs=() outputs=()
  merge_command=$1; shift
  for cmd do
    eval "coproc $cmd $close_in $close_out"

    exec {i}<&p {o}>&p
    inputs+=($i) outputs+=($o)
    eval i$n=$i o$n=$o
    close_in+=" {i$n}<&-" close_out+=" {o$n}>&-"
    ((n++))
  done
  coproc :
  read -p
  eval tee /dev/fd/$^outputs $close_in "> /dev/null &
    " exec $merge_command /dev/fd/$^inputs $close_out
)

Sau đó sử dụng như:

$ echo abcd | pee 'paste -d,' 'tr a A' 'tr b B' 'tr c C'
Abcd,aBcd,abCd

Điều đó được điều chỉnh từ câu hỏi khác này , nơi bạn sẽ tìm thấy một số giải thích chi tiết và gợi ý về những hạn chế (hãy cẩn thận với những bế tắc!).


0

Đối với ví dụ cụ thể của bạn, không cần pastevà phần còn lại. Điều thường đúng là khi chúng ta gặp phải một giới hạn với bộ công cụ tiêu chuẩn thì đó là vì những gì chúng ta muốn làm theo cách này có thể được thực hiện theo cách khác. Nhu la:

set 1 2 3 4
while [ "$#" -gt 0 ]
do    echo "$1" "$#" "$(($1*2))"
shift;done

... mà in ...

1 4 2
2 3 4
3 2 6
4 1 8

Bạn có thể nhận được một tệp có nội dung như bạn đề cập đến "$@"mảng shell của bạn như ...

set -f; IFS='
'; set -- $(cat)

Và để xác thực các giá trị arg trong một vòng lặp như ở trên, bạn có thể thay đổi thử nghiệm ban đầu một chút ...

while { [ "$1" -eq "${1-1}" ] ;} 2>&"$((2+!$#))"
do    echo "$1" "$#" "$(($1*2))"
shift;done  3>/dev/null >outfile

... chỉ in một lỗi thành stderr nếu một dòng được đọc với set -- $(cat)chứa một dòng không bao gồm hoàn toàn một số nguyên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.