Bash: Erfassen / Verwenden Sie die letzte (oder N-te) Zeile in stdout


11

Abfrage

Ich benutze Bash. Wenn ich nach Dateien suche, mache ich oft Folgendes:

find -name stackexchange.hs

Und oft sehen die Ergebnisse so aus:

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

Dann möchte ich einen der folgenden Schritte ausführen:

  • Option 1: Öffnen Sie das letzte Element in der Ergebnisliste in vim .
  • Option 2: Öffnen Sie das n-te Element in der Ergebnisliste in vim .

Derzeit schneide und füge ich mit der Maus ein. Was mich zu meiner Frage bringt :

  1. Gibt es einen einfachen Einzeiler, um die Optionen 1 und 2 zu erreichen? Beachten Sie, dass dies nach dem findBefehl erfolgt.
  2. Gibt es eine Möglichkeit, N-Linien von stdout in einer Art Bash-Vektor / Array zu erfassen?

Ideale Verwendung

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

(Syntax und Semantik können unterschiedlich sein, aber Sie verstehen es)

Similaria

Es scheint mehrere ähnliche Fragen zu geben. Hier sind meine wahrgenommenen Unterschiede (ich bin offen für Erleuchtung):

Danke für deine Hilfe! Nachdem ich als Teenager in den 90ern * nix / BSD verwendet habe und Angst hatte, indem ich meinen Burnout-Nachbarn anrief, um Treiber für meine Plug-and-Play-Soundkarte zu installieren, bin ich erleichtert, über Befehle zu sprechen. Linienminutien mit (wahrnehmbar) weniger beängstigenden Personen. Es fühlt sich gut an, zurück zu sein.


Ich denke, wenn Sie es vorher wissen, dass Sie das letzte Ergebnis öffnen möchten, könnten Sie so etwas verwenden vim $(command |tail -n1).
Varesa

Ich habe eine ähnliche Frage hier gepostet unix.stackexchange.com/questions/348224/…
joelostblom

Antworten:


8

Hier ist eine mögliche Lösung für Ihr Problem, die bei funky Dateinamen einigermaßen (aber nicht perfekt) sicher sein sollte (behandelt Dateinamen mit Zeilenvorschüben nicht - wahrscheinlich behebbar, aber möglicherweise lauern andere Probleme).

Zwei Funktionen, die erste wird findmit den Parametern ausgeführt, die Sie übergeben, speichern die Ausgabe in einem Array und zeigen sie an. Der zweite ist nur ein Helfer für den Zugriff auf dieses Array.

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

Anwendungsfall:

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

Anführungszeichen sind nicht erforderlich, $(myget index)wenn Sie keine Leerzeichen oder andere störende Zeichen in Ihren Dateinamen haben.
Überträgt die gesamte Ausgabe findin Ihre Umgebung, was möglicherweise eingeschränkt ist. (Die Verwendung einer temporären Datei anstelle dieses Arrays würde das lösen, hat jedoch andere Probleme - insbesondere die gleichzeitige Verwendung mehrerer Shells.)


1
Ich kann dich nicht upvoten, weil ich nicht genug von einem guten Ruf habe, also hier ist ein verbaler: "upvote"
aaronlevin

6

Ich habe das in meinem .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

Grundsätzlich wird auf dem Bildschirm ¬1die Zeile über dem Cursor ¬2eingefügt, die zweite Zeile über dem Cursor eingefügt ... und so weiter. Möglicherweise möchten Sie mehr für Zeilen 10 und höher hinzufügen, aber ich finde, dass ich bereits nach ungefähr 7 lieber die Maus oder den Kopiermodus verwenden möchte, screenals die Anzahl der Zeilen zu zählen, um die gewünschte zu erhalten.


0

Eine andere Lösung ist: Sie können ein interaktives Skript schreiben, das automatisch nach Ihrer Wahl fragt. Hier ist der Code für interaktives Skript:

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

Speichern Sie dieses Skript mit einem beliebigen Namen, sagen Sie "autofind", und rufen Sie das Skript mit Ihrem "find command" auf. Als Argument gibt es hier den Code zum Aufrufen des Skripts:

./autofind `your find command`

Bevor Sie das Skript verwenden, überprüfen Sie Ihren "Suchbefehl", ob er ein Ergebnis liefert oder nicht. Wenn ein Ergebnis angezeigt wird, verwenden Sie nur das Skript


0

Mats Antwort war genau das, wonach ich gesucht habe. Ich habe seinen Code ein wenig erweitert, um mehr Get-Optionen zu ermöglichen.

$ 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
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.