Автоматически записывать выходные данные последней команды в переменную, используя Bash?

Я хотел бы иметь возможность использовать результат последней выполненной команды в следующей команде. Например,

$ find . -name foo.txt
./home/user/some/directory/foo.txt

Теперь скажем, что я хочу иметь возможность открыть файл в редакторе или удалить его или сделать что-то еще с ним, например.

mv <some-variable-that-contains-the-result> /some/new/location

Как я могу это сделать? Может быть, с помощью некоторой переменной bash?

Update:

Чтобы уточнить, я не хочу назначать вещи вручную. Для меня что-то похоже на встроенные переменные bash, например.

ls /tmp
cd $_

$_ содержит последний аргумент предыдущей команды. Я хочу нечто подобное, но с выходом последней команды.

Окончательное обновление:

Ответ Сета сработал неплохо. Несколько вещей, которые нужно иметь в виду:

  • не забывайте touch /tmp/x при попытке решения в первый раз
  • результат будет сохранен только при успешном завершении кода последней команды.

Ответ 1

Это действительно хакерское решение, но, похоже, оно работает в большинстве случаев. Во время тестирования я заметил, что иногда это не очень хорошо работает при получении ^C в командной строке, хотя я немного изменил его поведение, чтобы немного поработать.

Этот хак - это только интерактивный режим, и я уверен, что не буду рекомендовать его никому. Фоновые команды, вероятно, вызовут еще менее определенное поведение, чем обычно. Другие ответы - лучший способ программного получения результатов.


Говоря это, вот "решение":

PROMPT_COMMAND='LAST="`cat /tmp/x`"; exec >/dev/tty; exec > >(tee /tmp/x)'

Установите эту переменную окружения bash и выдает команды по желанию. $LAST обычно будет выводить результат, который вы ищете:

startide seth> fortune
Courtship to marriage, as a very witty prologue to a very dull play.
                -- William Congreve
startide seth> echo "$LAST"
Courtship to marriage, as a very witty prologue to a very dull play.
                -- William Congreve

Ответ 2

Я не знаю никакой переменной, которая делает это автоматически. Чтобы сделать что-то помимо просто скопирования результата, вы можете повторно запустить все, что вы только что сделали, например

vim $(!!)

Где !! - расширение истории, означающее "предыдущая команда".

Если вы ожидаете, что в нем будет одно имя файла с пробелами или другими символами, которые могут помешать правильному анализу аргументов, укажите результат (vim "$(!!)"). Если оставить его без кавычек, он будет открывать сразу несколько файлов, если они не содержат пробелов или других токенов синтаксического анализа.

Ответ 3

Bash - это своего рода уродливый язык. Да, вы можете назначить вывод переменной

MY_VAR="$(find -name foo.txt)"
echo "$MY_VAR"

Но лучше надейтесь, что твой самый трудный find вернул только один результат и что у этого результата не было никаких "нечетных" символов в нем, таких как возврат каретки или линейных фидов, так как они будут тихо изменены при назначении к переменной Bash.

Но лучше быть осторожным, чтобы правильно указывать вашу переменную при ее использовании!

Лучше действовать непосредственно в файле, например. с find -execdir (обратитесь к руководству).

find -name foo.txt -execdir vim '{}' ';'

или

find -name foo.txt -execdir rename 's/\.txt$/.xml/' '{}' ';'

Ответ 4

Существует несколько способов сделать это. Один из способов - использовать v=$(command), который назначит вывод команды v. Например:

v=$(date)
echo $v

И вы также можете использовать backquotes.

v=`date`
echo $v

Из Bash Руководство для начинающих,

Когда используется обратная косая форма старого стиля, обратная косая черта сохраняет свое буквальное значение, за исключением случаев, когда следуют "$", "`" или "\". Первые обратные линии, не предшествующие обратному косую черту, завершают замену команды. При использовании формы "$ (COMMAND)" все символы между круглыми скобками составляют команду; ни один из них не рассматривается специально.

EDIT: после редактирования в вопросе кажется, что это не то, что ищет OP. Насколько мне известно, для вывода последней команды нет специальной переменной типа $_.

Ответ 5

Это довольно легко. Использовать обратные кавычки:

var=`find . -name foo.txt`

И тогда вы можете использовать это в любое время в будущем

echo $var
mv $var /somewhere

Ответ 6

Я думаю, что вы можете взломать решение, которое включает настройку оболочки на script, содержащую:

#!/bin/sh
bash | tee /var/log/bash.out.log

Затем, если вы установите $PROMPT_COMMAND для вывода разделителя, вы можете написать вспомогательную функцию (возможно, называемую _), которая вы получите последний кусок этого журнала, поэтому вы можете использовать его как:

% find lots*of*files
...
% echo "$(_)"
... # same output, but doesn't run the command again

Ответ 7

Disclamers:

  • Этот ответ длится полгода: D
  • Я тяжелый пользователь tmux.
  • Вы должны запустить свою оболочку в tmux для этого, чтобы работать

При запуске интерактивной оболочки в tmux вы можете легко получить доступ к данным, отображаемым в настоящее время на терминале. Давайте рассмотрим некоторые интересные команды:

  • панель захвата tmux: она копирует отображаемые данные в один из внутренних буферов tmux. Он может скопировать историю, которая в настоящее время не видна, но сейчас нас это не интересует.
  • tmux list-buffers: отображает информацию о захваченных буферах. Новейший номер будет иметь номер 0.
  • tmux show-buffer -b (buffer num): это печатает содержимое данного буфера на терминале
  • tmux paste-buffer -b (buffer num): это вставляет содержимое данного буфера в качестве входного

Да, это дает нам много возможностей.:) Что касается меня, я создал простой псевдоним: alias L="tmux capture-pane; tmux showb -b 0 | tail -n 3 | head -n 1" и теперь каждый раз, когда мне нужно получить доступ к последней строке, я просто использую $(L) для его получения.

Это не зависит от выходного потока, который использует программа (будь то stdin или stderr), метода печати (ncurses и т.д.) и кода выхода программы - данные просто должны отображаться.

Ответ 8

Вы можете настроить следующий псевдоним в своем профиле bash:

alias s='it=$($(history | tail -2 | head -1 | cut -d" " -f4-))'

Затем, набрав 's' после произвольной команды, вы можете сохранить результат в переменную оболочки 'it'.

Таким образом, пример использования:

$ which python
/usr/bin/python
$ s
$ file $it
/usr/bin/python: symbolic link to `python2.6'

Ответ 9

Я просто отстранил эту функцию bash от предложений здесь:

grab() {     
  grab=$("[email protected]")
  echo $grab
}

Затем вы просто выполните:

> grab date
Do 16. Feb 13:05:04 CET 2012
> echo $grab
Do 16. Feb 13:05:04 CET 2012

Обновить: анонимный пользователь предложил заменить echo на printf '%s\n', что имеет то преимущество, что он не обрабатывает такие параметры, как -e в захваченном тексте. Итак, если вы ожидаете или испытываете такие особенности, рассмотрите это предложение. Другой вариант - вместо этого использовать cat <<<$grab.

Ответ 10

Захват вывода с помощью backticks:

output=`program arguments`
echo $output
emacs $output

Ответ 11

Говоря "Я хочу, чтобы иметь возможность использовать результат последней выполненной команды в следующей команде", Я предполагаю, что вы имеете в виду результат любой команды, а не только найти.

Если это случай - xargs - это то, что вы ищете.

find . -name foo.txt -print0 | xargs -0 -I{} mv {} /some/new/location/{}

ИЛИ, если вам интересно сначала увидеть результат:

find . -name foo.txt -print0

!! | xargs -0 -I{} mv {} /some/new/location/{}

Эта команда имеет дело с несколькими файлами и работает как шарм, даже если путь и/или имя файла содержат пробелы.

Обратите внимание на часть mv {}/some/new/location/{}. Эта команда создается и выполняется для каждой строки, напечатанной более ранней командой. Здесь строка, напечатанная более ранней командой, заменяется вместо {}.

Отрывок из man-страницы xargs:

xargs - создавать и выполнять командные строки со стандартного ввода

Подробнее см. справочную страницу: man xargs

Ответ 12

Я обычно делаю то, что предлагали другие здесь... без назначения:

$find . -iname '*.cpp' -print
./foo.cpp
./bar.cpp
$vi `!!`
2 files to edit

Если вам нравится:

$grep -R "some variable" * | grep -v tags
./foo/bar/xxx
./bar/foo/yyy
$vi `!!`

Ответ 13

Если вы хотите только перезапустить свою последнюю команду и получить результат, будет работать простая переменная bash:

LAST=`!!`

Итак, вы можете запустить свою команду на выходе с помощью:

yourCommand $LAST

Это вызовет новый процесс и повторит вашу команду, а затем даст вам результат. Похоже на то, что вам действительно понравится, - это файл истории bash для вывода команды. Это означает, что вам нужно будет записать вывод, который bash отправляет на ваш терминал. Вы могли бы написать что-то, чтобы посмотреть /dev или/proc необходимые, но это беспорядочно. Вы также можете создать "специальную трубку" между вашим термином и bash с помощью команды tee в середине, которая перенаправляет ваш выходной файл.

Но оба эти типа являются хакерскими решениями. Я думаю, что лучше всего terminator, который является более современным терминалом с протоколированием выходных данных. Просто проверьте файл журнала для результатов последней команды. Переменная bash, аналогичная приведенной выше, сделает это еще проще.

Ответ 14

Здесь один из способов сделать это после выполнения вашей команды и решил, что вы хотите сохранить результат в переменной:

$ find . -name foo.txt
./home/user/some/directory/foo.txt
$ OUTPUT=`!!`
$ echo $OUTPUT
./home/user/some/directory/foo.txt
$ mv $OUTPUT somewhere/else/

Или, если вы заранее знаете, что хотите получить результат в переменной, вы можете использовать обратные ссылки:

$ OUTPUT=`find . -name foo.txt`
$ echo $OUTPUT
./home/user/some/directory/foo.txt

Ответ 15

Как альтернатива существующим ответам: используйте while, если ваши имена файлов могут содержать пробелы, подобные этому:

find . -name foo.txt | while IFS= read -r var; do
  echo "$var"
done

Как я уже писал, разница имеет смысл только в том случае, если вам нужно ожидать пробелов в именах файлов.

NB: единственный встроенный материал - это не о выходе, а о статусе последней команды.

Ответ 16

как добавить export $last=$(!!) в ваши .bashrc или .profile файлы?

EDIT: Не обращайте внимания на всевозможные глупости.

ИЗМЕНИТЬ № 2:

  • Загрузите bash исходный код
  • Узнать CPP
  • Код в новой магической переменной
  • Profit?

Ответ 17

вы можете использовать!!: 1. Пример:

~]$ ls *.~
class1.cpp~ class1.h~ main.cpp~ CMakeList.txt~ 

~]$ rm !!:1
rm class1.cpp~ class1.h~ main.cpp~ CMakeList.txt~ 


~]$ ls file_to_remove1 file_to_remove2
file_to_remove1 file_to_remove2

~]$ rm !!:1
rm file_to_remove1

~]$ rm !!:2
rm file_to_remove2

Ответ 18

У меня была аналогичная потребность, в которой я хотел использовать вывод последней команды в следующую. Очень похоже на | (Труба). например,

$ which gradle 
/usr/bin/gradle
$ ls -alrt /usr/bin/gradle

к чему-то вроде -

$ which gradle |: ls -altr {}

Решение: Создал эту настраиваемую трубку. Действительно просто, используя xargs -

$ alias :='xargs -I{}'

В принципе ничего, создавая короткую руку для xargs, она работает как шарм и очень удобна. Я просто добавляю псевдоним в файл .bash_profile.

Ответ 19

Это не строго решение bash, но вы можете использовать piping с sed для получения последней строки предыдущих команд.

Сначала давайте посмотрим, что у меня есть в папке "a"

[email protected]::~$ find a
a
a/foo
a/bar
a/bat
a/baz
[email protected]::~$ 

Затем ваш пример с ls и cd превратится в sed и piping в нечто вроде этого:

[email protected]::~$ cd `find a |sed '$!d'`
[email protected]::~/a/baz$ pwd
/home/rasjani/a/baz
[email protected]::~/a/baz$

Итак, реальная магия случается с sed, вы делаете то, что когда-либо выводило из когда-либо команды в sed и sed, печатает последнюю строку, которую вы можете использовать в качестве параметра с обратными тиками. Или вы можете комбинировать это с xargs также. ( "человек xargs" в оболочке - ваш друг)

Ответ 20

find . -name foo.txt 1> tmpfile && mv `cat tmpfile` /path/to/some/dir/

- это еще один способ, хотя и грязный.

Ответ 21

В оболочке нет perl-подобных специальных символов, которые сохраняют результат эха последней команды.

Научитесь использовать символ трубы с awk.

find . | awk '{ print "FILE:" $0 }'

В приведенном выше примере вы можете сделать:

find . -name "foo.txt" | awk '{ print "mv "$0" ~/bar/" | "sh" }'