Bash: Stdout'ta son (veya Nth) satırı yakala / kullan


11

Sorgu

Bash kullanıyorum. Dosyaları ararken genellikle aşağıdakileri yapacağım:

find -name stackexchange.hs

Ve genellikle sonuçlar şöyle görünecektir:

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

Sonra aşağıdakilerden birini yapmak isteyeceğim:

  • Seçenek 1: Sonuç listesindeki son öğeyi vim olarak açın .
  • 2. Seçenek: içinde sonuç listesinde Açık N. öğesi vim .

Şu anda fare ile kesip yapıştırıyorum. Bu da beni soruma getiriyor :

  1. Seçenek 1 ve 2'yi gerçekleştirmek için kolay, tek bir astar var mı? Bunun gerçekleşmesini unutmayın sonrafind komuta.
  2. Bir çeşit bash vektörü / dizisinde stdout'tan N-çizgileri yakalamanın bir yolu var mı?

İdeal kullanım

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

(sözdizimi ve anlambilim farklı olabilir, ancak konuyu anlayabilirsiniz)

Similaria

Birkaç benzer soru var gibi görünüyor. İşte benim algılanan farklarım (aydınlanmaya açıkım):

Yardımın için teşekkürler! 90'lı yaşlarda gençken * nix / BSD kullandıktan ve tak ve çalıştır ses kartım için sürücüleri yüklememe yardımcı olmak için tükenmişlik, asit kafalı komşumu arayarak korkuyorum, daha az korkutucu bireylerle (algılanabilir şekilde) minutiae. Geri dönmek iyi hissettiriyor.


Bence, eğer daha önce biliyorsan, son sonucu açmak istiyorsan, böyle bir şey kullanabilirsin vim $(command |tail -n1).
varesa

Burada benzer bir soru yayınladım unix.stackexchange.com/questions/348224/…
joelostblom

Yanıtlar:


8

İşte sorununuzu , funky dosya adlarının varlığında makul (ancak mükemmel değil) güvenli olması gereken olası bir çözümdür (dosya satırlarını satır satırlarıyla işlemez - muhtemelen düzeltilebilir, ancak gizlenen başka sorunlar olabilir).

İki işlev, birincisi geçirdiğiniz findparametrelerle çalışır , çıkışı bir diziye kaydeder ve görüntüler. İkincisi, bu diziye erişmek için sadece bir yardımcıdır.

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

Kullanım örneği:

$ 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)Dosya adlarınızda boşluk veya başka zahmetli karakterler yoksa, tırnak işaretleri gerekli değildir. Ortamınızın
tüm çıktısını findsınırlı tutabilir. (Bu dizi yerine geçici bir dosya kullanmak bunu çözer, ancak başka sorunları da vardır - özellikle birden fazla kabuktan eşzamanlı kullanım.)


1
Seni oylayamıyorum çünkü yeterince üne sahip değilim, işte burada bir, uh, sözel olan: "upvote"
aaronlevin

6

Bu benim var .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

Temel olarak, ekranda, ¬1imlecin üzerindeki çizgiyi yapıştırır, imlecin ¬2üzerindeki ikinci çizgiyi yapıştırır ... vb. 10 ve üzeri satırlar için daha fazla eklemek isteyebilirsiniz, ancak yaklaşık 7'den sonra, istediğim screençizgiyi elde etmek için satır sayısını saymak yerine fareyi veya kopya modunu kullanmayı tercih ederim .


0

başka bir çözüm: otomatik olarak seçiminizi soracak etkileşimli bir komut dosyası yazabilirsiniz. etkileşimli komut dosyası için kod:

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

Bu komut dosyasını herhangi bir adla kaydet "autofind" deyin ve betiği "find komutunuz" ile çağırın.

./autofind `your find command`

Ancak komut dosyasını kullanmadan önce "find komutunu" sonuç verip vermediğini kontrol edin.Bazı sonuç gösteriyorsa, sadece betiği kullanın


0

Mats cevap aradığım şeydi. Daha fazla seçenek almak için onun kodunu biraz genişlettim.

$ 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
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.