Bash: захоплення / використання останнього (або N-го) рядка в 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: Відкрийте останній елемент у списку результатів in vim .
  • Варіант 2: Відкрийте N-й елемент у списку результатів in vim .

В даний час я вирізаю і вставляю мишу. Що підводить мене до мого питання :

  1. Чи є легкий однолінійний варіант для виконання варіантів 1 і 2? Зверніть увагу , що це відбувається після того, як в findкоманді.
  2. Чи є спосіб зафіксувати N-рядки з stdout в якомусь баш-векторі / масиві?

Ідеальне використання

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

(синтаксис і семантика можуть відрізнятися, але ви розумієте)

Симілярія

Схоже, є кілька подібних питань. Ось мої сприйняті відмінності (я відкритий до просвітлення):

Дякую за твою допомогу! Використовуючи * nix / BSD, коли я був підлітком у 90-х, і злякався, зателефонувавши моєму вигоранню, кислотному голові сусіда, щоб допомогти мені встановити драйвери для моєї звукової карти підключення і відтворення, я полегшу обговорити команду- рядкові деталі з (мабуть) менш лякаючими особами. Відчуває себе добре повернутися.


Я думаю, що якщо ви знаєте це раніше, то хочете відкрити останній результат, ви могли б скористатися чимось подібним vim $(command |tail -n1).
Вареза

Я розмістив подібне запитання тут unix.stackexchange.com/questions/348224/…
joelostblom

Відповіді:


8

Ось потенційне рішення вашої проблеми, яке повинно бути розумно (але не досконало) безпечним за наявності прикольних імен файлів (не обробляє імена файлів із стрічковими каналами в них - можливо, виправлено, але можуть виникнути інші проблеми).

Дві функції, перша працює 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 command", оскільки аргументом є код для виклику скрипту:

./autofind `your find command`

Перш ніж використовувати скрипт, перевірте свою команду "знайти", дає вона результат чи ні. Якщо вона показує якийсь результат, тоді використовуйте лише скрипт


0

Відповідь Матса - це саме те, що я шукав. Я трохи розширив його код, щоб отримати більше варіантів get.

$ 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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.