Включить команду в выходной файл?


17

Извините за запутанный заголовок!

Предположим, я бегу

apt-cache depends kde-window-manager > ~/Desktop/kwin-depends

Я получу файл с именем "kwin-disabled" в папке Desktop.

Есть ли какая-то хитрость, чтобы включить команду, которую я дал как часть файла, предпочтительно в начале файла?

Итак, по крайней мере в 14.04 LTS первые несколько строк будут выглядеть так:

apt-cache depends kde-window-manager > ~/Desktop/kwin-depends

kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>

Вместо того, чтобы просто так:

kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>

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

Ответы:


18

Я бы просто использовал простую функцию. Добавьте это в ваш ~/.bashrcфайл:

function runcom(){
    echo "$@"
    ## Run the command
    $@
}

Теперь, когда вы хотите запустить команду и распечатать ее, вы можете сделать:

runcom apt-cache depends kde-window-manager > out

Выше приведен этот файл:

$ cat out
apt-cache depends kde-window-manager
kde-window-manager
  Depends: perl
  Depends: kde-runtime
  Depends: kde-style-oxygen
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
    libegl1-mesa
  Depends: libgcc1
 |Depends: libgl1-mesa-glx
  Depends: <libgl1>
    libgl1-mesa-swx11
    libgl1-mesa-glx
 |Depends: libgles2-mesa
  Depends: <libgles2>
    libgles2-mesa
  Depends: libice6
  Depends: libkactivities6
  Depends: libkcmutils4
  Depends: libkdeclarative5
  Depends: libkdecorations4abi2
  Depends: libkdecore5
  Depends: libkdeui5
  Depends: libkio5
  Depends: libknewstuff3-4
  Depends: libkwineffects1abi5
  Depends: libkwinglesutils1
  Depends: libkwinglutils1abi2
  Depends: libkworkspace4abi2
  Depends: libplasma3
  Depends: libqt4-dbus
  Depends: libqt4-declarative
  Depends: libqt4-script
  Depends: libqtcore4
  Depends: libqtgui4
  Depends: libsm6
  Depends: libstdc++6
  Depends: libwayland-client0
 |Depends: libwayland-egl1-mesa
  Depends: <libwayland-egl1>
    libwayland-egl1-mesa
  Depends: libx11-6
  Depends: libx11-xcb1
  Depends: libxcb-composite0
  Depends: libxcb-damage0
  Depends: libxcb-image0
  Depends: libxcb-keysyms1
  Depends: libxcb-randr0
  Depends: libxcb-render0
  Depends: libxcb-shape0
  Depends: libxcb-shm0
  Depends: libxcb-sync1
  Depends: libxcb-xfixes0
  Depends: libxcb-xtest0
  Depends: libxcb1
  Depends: libxcursor1
  Depends: libxext6
  Depends: libxrandr2
  Depends: libxxf86vm1
  Breaks: kde-style-bespin
  Breaks: kde-style-bespin:i386
  Breaks: <kde-style-skulpture>
  Breaks: <kde-style-skulpture:i386>
  Breaks: kde-workspace-data
  Breaks: <kde-workspace-data:i386>
  Breaks: kdeartwork-theme-window
  Breaks: kdeartwork-theme-window:i386
  Breaks: <kdebase-workspace-data>
  Breaks: <kdebase-workspace-data:i386>
  Breaks: kwin-style-crystal
  Breaks: kwin-style-crystal:i386
  Breaks: kwin-style-dekorator
  Breaks: kwin-style-dekorator:i386
  Breaks: kwin-style-qtcurve
  Breaks: kwin-style-qtcurve:i386
  Replaces: kde-workspace-data
  Replaces: <kde-workspace-data:i386>
  Replaces: <kdebase-workspace-data>
  Replaces: <kdebase-workspace-data:i386>
  Conflicts: kde-window-manager:i386

Я не хочу переносить здесь стойку ворот, но есть ли способ заставить ваш код также принимать псевдонимы? Например, если я псевдоним , apt-cache dependsчтобы acdя получаю «Нет команды„ДС“найдено, вы имели в виду: ...» , когда я бег runcom acd leafpad > out.
ДК Бозе

Псевдонимы @DKBose определены в файле .bashrc, а не в оболочке, и функции вызывают только двоичные файлы, которые находятся в переменной $ PATH. Но вы можете сделать простой трюк. Например, lsпсевдоним ls --color=auto' в реальности. Что вы могли бы сделать ( до тех пор, пока не будет ни одного одинарных или двойные кавычек в псевдониме), заключается в следующем: $ terdonsFunction $(alias ls | awk -F '=' '{$1="";print}'| tr "'" " ") .
Сергей Колодяжный

ИЛИ превратить вашу команду в переменную. Как я показал в своем ответе раньше. MYCOMMAND="apt-cache depends"; terdonsFunction $MYCOMMAND leafpad > out.txt
Сергей Колодяжный

@Serg, см. ГАРЦИН Ответ Дэвида: askubuntu.com/a/688936/248158
ДК Бозе

Это «очевидный» ответ и прекрасно работает, если ни один из аргументов не включает в себя код, который выполняется и имеет побочные эффекты, которые могут накапливаться. Это крайний случай, поэтому он не будет происходить очень часто.
Джо

11

Ты можешь сделать:

tee file.txt <<<'apt-cache depends kde-window-manager' | bash >>file.txt

То же самое, используя echoвместо строк здесь ( <<<):

echo 'apt-cache depends kde-window-manager' | tee file.txt | bash >>file.txt
  • tee будет писать в STDOUT, а также в файл file.txt

  • STDOUT из teeie apt-cache depends kde-window-managerбудет использоваться bashдля запуска команды и добавления STDOUT к file.txt.

Пример:

$ echo 'apt-cache depends kde-window-manager' | tee file.txt | bash >>file.txt

$ cat file.txt 
apt-cache depends kde-window-manager
kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>

1
Отличный ответ! Просто и точно! Я пробовал один с, teeно мой продолжал терпеть неудачу. Молодец! +1
Терренс

@Seth Я также думал о том, чтобы поиграть с файловыми дескрипторами, но, teeкажется, аккуратно :)
heemayl

11

Наиболее минималистичный подход № 4 и № 3, оба могут быть преобразованы в функцию; № 2 мой любимый - awk. # 1 использует scriptкоманду - очень универсальный инструмент, полезный для записи командной строки в целом; применимо где угодно, для всего, что вы хотите записать.

Подход № 1: Существует /usr/bin/scriptкоманда (которая поставляется с ubuntu по умолчанию) для записи выходных данных командной строки, которая захватывает все вместе с приглашением и командой. Чтобы просто сохранить одну команду и ее вывод в конкретный файл, используйте-c флаг и укажите выходной файл. пример

xieerqi:$ script -c 'apt-cache depends gnome-terminal' outputFile.txt
Script started, file is outputFile.txt
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
     (extra output omitted)
Script done, file is outputFile.txt

xieerqi:$ cat outputFile.txt                                              
Script started on 20151022 星期四 085846
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  (extra output omitted)

Script done on 20151022 星期四 085846

Подход № 2: awk взломать

Awk имеет system()функцию, которая позволяет запускать команды оболочки из awkскрипта или команды . Вывод будет отображаться на экране, сначала команда, затем выход. Чтобы перенаправить увиденное в файл, используйте >оператор.

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

(1) awk 'BEGIN{ print "Enter command to run: "; getline com < "/dev/stdin"; system(com) }'

 awk 'BEGIN{ print "Enter command to run: "; getline com < "/dev/stdin"; system(com) }'
Enter command to run: 
apt-cache depends gnome-terminal
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
  Depends: libglib2.0-0 
  (extra output omitted)

(2) версия аргументов командной строки; не включая вывод, чтобы избежать слишком длинного ответа. Снова, добавьте, >чтобы перенаправить в файл

awk 'BEGIN{for (i=1; i<= ARGC; i++) myString = myString"  "ARGV[i]; print myString; system(myString)  }' apt-cache depends gnome-terminal

Подход № 3: попросите Bash сделать работу за вас

xieerqi@eagle:~$ bash -c ' MYCOMMAND="apt-cache depends gnome-terminal"; echo $MYCOMMAND ; $MYCOMMAND    '
apt-cache depends gnome-terminal
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
  Depends: libglib2.0-0

Перенаправить в файл с >оператором:

bash -c ' MYCOMMAND="apt-cache depends gnome-terminal"; echo $MYCOMMAND ; $MYCOMMAND ' > output.txt

Подход № 4: (мой второй любимый)

Вдохновленный постом ByteCommander; мы можем использовать, readа затем запустить необходимые команды в subshell

read command && (printf "COMMAND: %s" "$command";printf "\n+++++++\n"; sh -c "$command")

Образец прогона:

xieerqi:$ read command && (printf "COMMAND READ: %s" "$command";printf "\n+++++++\nOUTPUT\n"; sh -c "$command")                                       
printf "This was a triumph; I'm making a note here - huge success"
COMMAND READ: printf "This was a triumph; I'm making a note here - huge success"
+++++++
OUTPUT
This was a triumph; I'm making a note here - huge success

Подход № 5:

Используйте echoили here string(иначе <<< "string") для предоставления аргументов sh -cчерезxargs

xieerqi:$ echo "apt-cache policy gnome-terminal" | xargs -I {} bash -c 'echo {}; {}'                                                            
apt-cache policy gnome-terminal
gnome-terminal:
  Installed: 3.6.2-0ubuntu1
  Candidate: 3.6.2-0ubuntu1
  Version table:
 *** 3.6.2-0ubuntu1 0
        500 http://us.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        100 /var/lib/dpkg/status

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

xieerqi:$ printAndRun <<< "apt-cache policy gnome-terminal"                                                                                     
apt-cache policy gnome-terminal
gnome-terminal:
  Installed: 3.6.2-0ubuntu1
  Candidate: 3.6.2-0ubuntu1
  Version table:
 *** 3.6.2-0ubuntu1 0
        500 http://us.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        100 /var/lib/dpkg/status

xieerqi:$ type printAndRun
printAndRun is an alias for 'xargs -I {} bash -c "echo {}; {}"'

Хорошо, но она не включает команду, как в коде Arronical.
ДК Бозе

@DKBose Я добавлю другой подход, который будет включать команду. Пять минут
Сергей Колодяжный

@DKBose как мой подход # 2?
Сергей Колодяжный

Это умно, на awkсамом деле это очень настраиваемый маленький парень, не так ли? Скрипт выглядит удобным и для других целей.
Arronical

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

6
  1. Начало script -q outputfile
  2. Выполнить вашу команду
  3. Нажмите Ctrl-D
  4. Открыть файл outputfile

пример

Начало script

[aboettger:~/tmp] % script -q ~/Desktop/kwin-depends

Начни свою команду

[aboettger:~/tmp] % apt-cache depends kde-window-manager
<kde-window-manager>
[aboettger:~/tmp] % 

Нажмите Ctrl-D

Script done, file is /home/aboettger/Desktop/kwin-depends

Покажите свою команду и вывод

[aboettger:~/tmp] % cat ~/Desktop/kwin-depends

и вы увидите что-то вроде этого

[aboettger:~/tmp] % apt-cache depends kde-window-manager
<kde-window-manager>

5

Если вы хотите расширение псевдонима (только bash), вы можете сделать это следующим образом:

function runcmd
{
    local check_cmd=${BASH_ALIASES[$1]}

    if [ -z "$check_cmd" ]; then
        check_cmd=$1
    fi

    shift #skip 1st arg

    echo "$check_cmd $@"
    $check_cmd $@
}

Теперь вы можете запустить

runcmd acd leafpad > out

4

Там может быть более простой способ, но вы можете сделать это с помощью сценария:

#!/bin/sh
echo $1
apt-cache depends $1

Создайте файл scriptс этим содержимым в вашей домашней папке и дайте разрешение на выполнение

chmod +x script

Запустите это так:

./script kde-window-manager > ~/Desktop/kwin-depends

Этот подход имеет то преимущество, что позволяет легко повторить эту командную строку позже, если вы хотите! Вы также можете записать перенаправление в скрипт, чтобы он script.shвсегда создавал файл script.logс его выводом.
Гаурав

4

Чрезвычайно простое решение с использованием однострочной функции Bash

Приготовление:

Этот подход использует пользовательскую функцию bash для обеспечения желаемой функциональности. Вы определяете это, выполняя следующую строку в терминальной сессии. обратите внимание, что вы можете выбрать любое допустимое имя переменной bash вместо runandlog:

runandlog () ( IFS=' '; printf "[%s] $ %s\n%s\n" "$USER" "${*:2}" "$("${@:2}")" | tee -a "$1" | tail -n +2; )

Это, однако, сохраняется только для текущего сеанса Bash, что означает, что после закрытия окна терминала функция исчезнет.
Если вы попробовали и понравились, вы можете сделать его всегда доступным, отредактировав свой ~/.bashrcфайл и добавив эту строку в конец.

Как пользоваться:

После определения функции вы можете использовать ее для запуска команд, одновременно регистрируя как саму команду, так и ее вывод в файл. Вы можете даже добавить больше информации, например, пользователя, который ее выполнил, который я уже включил в функцию, или точное время ее запуска. Feature-запросы в комментариях приветствуются! :)

Синтаксис прост:

runandlog LOGFILENAME YOUR-COMMAND-WITH-ARGUMENTS

Пример:

Пример сеанса от имени пользователя bytecommander, работающего из домашнего каталога, может выглядеть так:

bytecommander: ~ $  runandlog mylogfile fortune
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos

Это приведет к созданию нового файла mylogfile (если он уже существует, функция добавит к нему вывод!) В текущем каталоге с содержимым:

[bytecommander] $ fortune 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos

3

Довольно хитрый, но функциональный трюк будет:

(echo "apt-cache depends kde-window-manager" && apt-cache depends kde-window-manager) > ~/Desktop/kwin-depends

Уродливо, но это работает!


Я принимаю этот ответ, потому что решение более широко применимо.
ДК Бозе

@DKBose Вам нужно будет дважды напечатать модуль. Но решение со скриптом действительно универсально.
Pilot6

Мне жаль, что я не принимаю этот ответ, хотя он и делает то, что я просил. Надеюсь, ты не против!
ДК Бозе

2
Не проблема @DKBose, я знал, что это было довольно не элегантное решение, когда отправлял ответ, и узнал кое-что хорошее из опубликованных альтернативных ответов.
Arronical

2

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

function myfunction() {
    printf "%s\n\n" "$1"
    $1
}
$ myfunction "printf \"bar\n\"" > foo
$ cat foo
printf "bar\n"

bar

Чтобы добавить команду впоследствии, вы можете запустить эту команду, которая вставит последнюю команду, выполненную вверху файла:

<<<"$(<foo)" cat <(history 2 | sed -n '1s/  [0-9][0-9]*  \(.*\)/\1\n/p') - >foo
  • <<<"[...]": здесь строка; [...]перенаправлен на cats stdin;
  • $(<foo): подстановка команд; это заменено содержанием "foo";
  • cat [...] - >foo: Сцепляет stdinк [...]и выводит на «Foo»;
  • <([...]): замена процесса: он заменяется дескриптором файла, содержащим выходные данные [...];
  • history 2 | sed -n '1s/ [0-9][0-9]* \(.*\)/\1\n/p': выводит последние две команды, удаляет два пробела, за которыми следуют одна или несколько цифр, за которыми следуют два пробела из первой строки, и печатает ее;
$ printf "bar\n" >foo
$ <<<"$(<foo)" cat <(history 2 | sed -n '1s/  [0-9][0-9]*  \(.*\)/\1\n/p') - >foo
$ cat foo
printf "bar" >foo

bar

Почему ты только печатаешь $1? И в этом нет необходимости eval.
тердон

@terdon Ну, идея состояла в том, чтобы не допускать перенаправления из печатной команды, так как я думал, что это могло бы выглядеть лучше в случае OP. Тем не менее, если я изменю это сейчас, это будет идентично вашему ответу. Однако да, evalне нужно, не уверен, почему я добавил это раньше. Благодарю.
Кос
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.