Bash: การจับภาพ / ใช้บรรทัดสุดท้าย (หรือ Nth) ใน stdout


11

สอบถาม

ฉันใช้ Bash เมื่อฉันค้นหาไฟล์บ่อยครั้งที่ฉันจะทำสิ่งต่อไปนี้:

find -name stackexchange.hs

และผลลัพธ์มักจะมีลักษณะดังนี้:

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

จากนั้นฉันจะทำอย่างใดอย่างหนึ่งต่อไปนี้:

  • ตัวเลือกที่ 1: เปิดรายการสุดท้ายในรายการผลลัพธ์ในกลุ่ม
  • ตัวเลือกที่ 2: เปิดรายการชับในรายการผลลัพธ์ในกลุ่ม

ปัจจุบันฉันตัดและวางด้วยเมาส์ ซึ่งนำมาสู่คำถามของฉัน:

  1. มีซับในหนึ่งเดียวที่ง่ายต่อการบรรลุตัวเลือกที่ 1 และ 2 หรือไม่? ทราบว่านี้เกิดขึ้นหลังจากที่findคำสั่ง
  2. มีวิธีจับ N-line จาก stdout ใน bash vector / array หรือไม่?

การใช้งานในอุดมคติ

$ 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)

(ไวยากรณ์และความหมายอาจแตกต่างกัน แต่คุณจะได้รับคะแนน)

Similaria

ดูเหมือนจะมีคำถามที่คล้ายกันหลายอย่าง นี่คือความแตกต่างที่ฉันรับรู้ (ฉันเปิดรับการตรัสรู้):

ขอขอบคุณสำหรับความช่วยเหลือของคุณ! การใช้ * nix / BSD เมื่อฉันเป็นวัยรุ่นใน 90s และเริ่มกลัวโดยเรียกความเหนื่อยล้าเพื่อนบ้านที่มีหัวกรดของฉันเพื่อช่วยฉันติดตั้งไดรเวอร์สำหรับการ์ดเสียงแบบ plug-and-play ฉันโล่งใจที่จะพูดคุยเกี่ยวกับคำสั่ง - สาย minutiae กับบุคคลที่น่ากลัวน้อยลง รู้สึกดีที่ได้กลับมา


vim $(command |tail -n1)ผมคิดว่าถ้าคุณจะรู้ว่าก่อนที่คุณต้องการที่จะเปิดผลสุดท้ายคุณอาจใช้สิ่งที่ต้องการ
varesa

ฉันโพสต์คำถามที่คล้ายกันที่นี่unix.stackexchange.com/questions/348224/ …
joelostblom

คำตอบ:


8

นี่เป็นวิธีแก้ปัญหาที่เป็นไปได้สำหรับปัญหาของคุณที่ควรมีความปลอดภัย (แต่ไม่สมบูรณ์) ในที่ที่มีชื่อไฟล์ที่ขี้ขลาด (ไม่ได้จัดการชื่อไฟล์ด้วย linefeeds ในนั้น - อาจแก้ไขได้

สองฟังก์ชั่นโดยฟังก์ชั่นแรกทำงานfindด้วยพารามิเตอร์ที่คุณส่งผ่านบันทึกเอาต์พุตในอาเรย์แล้วแสดงผล ประการที่สองเป็นเพียงผู้ช่วยในการเข้าถึงอาร์เรย์นั้น

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

ใช้กรณี:

$ 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"

ไม่ต้องใส่เครื่องหมายคำพูด$(myget index)หากคุณไม่มีช่องว่างหรือตัวอักษรที่มีปัญหาอื่น ๆ ในชื่อไฟล์ของคุณ
ผลักดันเอาต์พุตทั้งหมดfindไปยังสภาพแวดล้อมของคุณซึ่งอาจถูก จำกัด (การใช้ไฟล์ชั่วคราวแทนที่จะใช้อาเรย์นั้นจะแก้ปัญหานั้น แต่มีปัญหาอื่น ๆ - โดยเฉพาะอย่างยิ่งการใช้งานพร้อมกันจากหลาย ๆ เชลล์)


1
ฉันไม่สามารถลงคะแนนให้คุณเพราะฉันมีชื่อเสียงไม่พอดังนั้นนี่คือหนึ่งเอ่อวาจาหนึ่ง: "upvote"
aaronlevin

6

ฉันได้รับสิ่งนี้ใน.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

โดยทั่วไปในหน้าจอ¬1วางเส้นเหนือเคอร์เซอร์¬2วางบรรทัดที่สองเหนือเคอร์เซอร์ ... และอื่น ๆ คุณอาจต้องการเพิ่มมากขึ้นสำหรับบรรทัดที่ 10 ขึ้นไป แต่ฉันพบว่าหลังจากผ่านไปประมาณ 7 ปีแล้วฉันควรใช้screenโหมดคัดลอกของเมาส์มากกว่าการนับจำนวนบรรทัดเพื่อรับสิ่งที่ฉันต้องการ


0

อีกวิธีคือ: คุณสามารถเขียนสคริปต์แบบโต้ตอบที่จะขอให้คุณเลือกโดยอัตโนมัติ นี่คือรหัสสำหรับสคริปต์แบบโต้ตอบ:

#!/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

บันทึกสคริปต์นี้ด้วยชื่อใด ๆ ที่พูดว่า "autofind" และเรียกใช้สคริปต์ด้วยคำสั่ง "find" ของคุณเนื่องจากอาร์กิวเมนต์ที่นี่คือรหัสที่จะเรียกใช้สคริปต์:

./autofind `your find command`

แต่ก่อนที่จะใช้สคริปต์ให้ตรวจสอบ "คำสั่งค้นหา" ของคุณว่าจะให้ผลหรือไม่ถ้ามันจะแสดงผลบางอย่างแล้วใช้สคริปต์เท่านั้น


0

คำตอบของ Mats เป็นเพียงสิ่งที่ฉันกำลังมองหา ฉันขยายโค้ดของเขาเล็กน้อยเพื่อให้ได้ตัวเลือกเพิ่มเติม

$ 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
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.