Bash: Capture / Sử dụng dòng cuối cùng (hoặc Nth) trong thiết bị xuất chuẩn


11

Truy vấn

Tôi sử dụng Bash. Khi tôi đang tìm kiếm các tập tin, tôi thường làm như sau:

find -name stackexchange.hs

Và thường thì kết quả sẽ như sau:

/youre/the/man/now/dog/stackexchange.hs
/you/are/no/longer/the/dog/dog/stackexchange.hs
/this/is/the/file/i/want/stackexchange.hs

Sau đó, tôi sẽ muốn làm một trong những điều sau đây:

  • Tùy chọn 1: Mở mục cuối cùng trong danh sách kết quả trong vim .
  • Tùy chọn 2: Mở mục thứ N trong danh sách kết quả trong vim .

Hiện tại, tôi cắt và dán bằng chuột. Điều này đưa tôi đến câu hỏi của tôi :

  1. Có dễ dàng, một lớp lót để thực hiện các tùy chọn 1 & 2 không? Lưu ý rằng điều này xảy ra sau khi các findlệnh.
  2. Có cách nào để bắt N-lines từ stdout trong một số loại bash vector / mảng không?

Cách sử dụng lý tưởng

$ find -name am_i_really_all_alone.txt
./borges/library/you_are_not_alone.txt
./borges/library/am_i_really_all_alone.txt
$ vim (N)

(cú pháp và ngữ nghĩa có thể khác nhau, nhưng bạn có được điểm)

Tương tự

Dường như có một số câu hỏi tương tự. Dưới đây là những khác biệt nhận thức của tôi (tôi mở ra cho sự giác ngộ):

Cảm ơn sự giúp đỡ của bạn! Đã sử dụng * nix / BSD khi tôi còn là một thiếu niên ở thập niên 90 và sợ hãi bằng cách gọi người kiệt sức của mình, người hàng xóm đầu axit để giúp tôi cài đặt trình điều khiển cho thẻ âm thanh plug-and-play của mình, tôi cảm thấy nhẹ nhõm khi thảo luận về lệnh- dòng minutiae với (cá nhân) ít đáng sợ hơn. Cảm thấy tốt khi được trở lại.


Tôi nghĩ rằng, nếu bạn biết trước đó rằng bạn muốn mở kết quả cuối cùng, bạn có thể sử dụng một cái gì đó như vim $(command |tail -n1).
varesa

Tôi đã đăng một câu hỏi tương tự ở đây unix.stackexchange.com/questions/348224/ trên
joelostblom

Câu trả lời:


8

Đây là một giải pháp tiềm năng cho vấn đề của bạn một cách hợp lý (nhưng không hoàn toàn) an toàn khi có tên tệp vui nhộn (không xử lý tên tệp có nguồn cấp dữ liệu trong chúng - có thể khắc phục được, nhưng có thể có các vấn đề khác đang ẩn giấu).

Hai hàm, hàm đầu tiên chạy findvới các tham số bạn truyền vào nó, lưu đầu ra trong một mảng và hiển thị chúng. Thứ hai chỉ là một người trợ giúp để truy cập vào mảng đó.

myfind() {
  IFS=$'\n' __last_find_result=($(find "$@"));
  printf "%s\n" "${__last_find_result[@]}";
}
myget() {
  echo "${__last_find_result[$1]}";
}

Trường hợp sử dụng:

$ myfind . -name "c*"
./a b/c d
./.git/config
./.git/hooks/commit-msg.sample
$ vim "$(myget 0)"
# This opens the "./a b/c d" file.
$ vim "$(myget 2)"
# This opens ".git/hooks/commit-msg.sample"

Các trích dẫn không bắt buộc xung quanh $(myget index)nếu bạn không có khoảng trắng hoặc các ký tự rắc rối khác trong tên tệp của bạn.
Đẩy toàn bộ đầu ra của findmôi trường của bạn, có thể bị hạn chế. (Sử dụng một tệp tạm thời thay vì mảng đó sẽ giải quyết được điều đó, nhưng có các vấn đề khác - đáng chú ý là sử dụng đồng thời từ nhiều hệ vỏ.)


1
Tôi không thể nâng cao bạn vì tôi không có đủ tiếng tăm, vì vậy đây là một, uh, bằng lời nói: "upvote"
aaronlevin

6

Tôi đã có cái này trong .screenrc:

bind -c pasteline 1 eval copy 'stuff "-Y"' 'paste .'
bind -c pasteline 2 eval copy 'stuff "2-Y"' 'paste .'
bind -c pasteline 3 eval copy 'stuff "3-Y"' 'paste .'
bind -c pasteline 4 eval copy 'stuff "4-Y"' 'paste .'
bind -c pasteline 5 eval copy 'stuff "5-Y"' 'paste .'
bind -c pasteline 6 eval copy 'stuff "6-Y"' 'paste .'
bind -c pasteline 7 eval copy 'stuff "7-Y"' 'paste .'
bind -c pasteline 8 eval copy 'stuff "8-Y"' 'paste .'
bind -c pasteline 9 eval copy 'stuff "9-Y"' 'paste .'
bindkey ¬ command -c pasteline

Về cơ bản, trong màn hình, ¬1dán dòng phía trên con trỏ ¬2, dán dòng thứ hai phía trên con trỏ ... và cứ thế. Bạn có thể muốn thêm nhiều hơn cho các dòng 10 trở lên, nhưng tôi thấy rằng sau khoảng 7 đã, tôi thà sử dụng screenchế độ sao chép của chuột hoặc hơn là đếm số lượng dòng để có được dòng tôi muốn.


0

một giải pháp khác là: bạn có thể viết một kịch bản tương tác sẽ tự động yêu cầu sự lựa chọn của bạn. đây là mã cho kịch bản tương tác:

#!/bin/bash

echo "enter your choice : z for last argument or a number for that file"
read choice

case "$choice" in
z) eval vim \$$#;;
*)eval  vim \$$choice;;
esac

lưu tập lệnh này với bất kỳ tên nào nói "tự động" và gọi tập lệnh bằng "lệnh tìm" của bạn vì đối số ở đây là mã để gọi tập lệnh:

./autofind `your find command`

Nhưng trước khi sử dụng tập lệnh, hãy kiểm tra "lệnh tìm" của bạn xem nó có cho kết quả hay không. Nếu nó hiển thị một số kết quả thì chỉ sử dụng tập lệnh


0

Câu trả lời của Mats chỉ là những gì tôi đang tìm kiếm. Tôi đã mở rộng mã của mình một chút để cho phép có thêm tùy chọn.

$ f ~/scripts -name '*.sh'
$ vim $(g foo)  # edit all find results matching "foo"
$ vim $(g 1 3 5) # edit find results number 1, 3 and 5
$ vim $(g 3-5) # edit find results 3-5
$ vim $(g 5-) # edit find results 5 to last
$ vim $(g -7) # edit find result 7 from bottom
$ vim $(g 1 4-5 -7 9- foo) # all of the above combined

.

f() {
    IFS=$'\n' __last_find_result=($(find "$@"));
    printf "%s\n" "${__last_find_result[@]}";
}

g() {
    len=${#__last_find_result[@]}
    pad=${#len}
    numbers=""
    if [ "$1" == "-n" ]; then
        numbers=1
        shift
    fi
    if [ -z "$1" ]; then
        if [ -n "$numbers" ]; then
            n=1;
            for e in "${__last_find_result[@]}";do
                printf "%0${pad}d. %s\n" "$n" "$e"
                let n=n+1
            done
        else
            printf "%s\n" "${__last_find_result[@]}"
        fi
    else
        for l in $@;do
            if [[ "$l" =~ ([^0-9-]+) ]];then
                n=1;
                for e in "${__last_find_result[@]}";do
                    if [[ $e =~ $1 ]]; then
                        if [ -n "$numbers" ];then
                            printf "%0${pad}d. %s\n" "$n" "$e"
                        else
                            printf "%s\n" "$e"
                        fi
                    fi
                    let n=n+1
                done
            elif [[ "$l" =~ ^([0-9]+)$ ]];then
                let l=l-1
                echo "${__last_find_result[$l]}";
            elif [[ "$l" =~ ^([0-9]*)(-)?([0-9]*)$ ]]; then
                from=${BASH_REMATCH[1]};
                dash=${BASH_REMATCH[2]};
                to=${BASH_REMATCH[3]};
                if [ -z "$from" ]; then # -n
                    [ $to -gt ${#__last_find_result[@]} ] && to=${#__last_find_result[@]}
                    echo "${__last_find_result[-$to]}";
                else # n-m
                    [ -z "$to" ] && to=${#__last_find_result[@]}
                    [ $to -gt ${#__last_find_result[@]} ] && to=${#__last_find_result[@]}
                    let to=$to-1
                    let from=$from-1
                    n=$(($from+1))
                    for i in `seq $from $to`;do
                        if [ -n "$numbers" ];then
                            printf "%0${pad}d. %s\n" "$n" "${__last_find_result[$i]}"
                        else
                            printf "%s\n" "${__last_find_result[$i]}"
                        fi
                        let n=n+1
                    done
                fi
            fi
        done
    fi
}
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.