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

Извините за запутанное название!

Предположим, что я запустил

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

Я получаю файл с именем «kwin-depends» в папке «Мой рабочий стол».

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

Итак, по крайней мере, в 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>
1
задан 22 October 2015 в 17:18

8 ответов

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

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 для tee, т.е. 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>
12
ответ дан 23 May 2018 в 16:29
  • 1
    Отличный ответ! Простой и точный! Я пытался с помощью tee, но мой продолжал терпеть неудачу. Отличная работа! +1 – Terrance 23 October 2015 в 01:04
  • 2
    @Seth Я также подумал о том, чтобы играть с файловыми дескрипторами, но tee кажется опрятным :) – heemayl 23 October 2015 в 07:10

Большинство минималистичных - подход № 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 2015年10月22日 星期四 08时58分46秒
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  (extra output omitted)

Script done on 2015年10月22日 星期四 08时58分46秒

Подход №1:

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

Это можно сделать двумя способами: попросите пользователя ввести материал из stdin или в качестве аргумента командной строки. [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) Версия командной строки args; не включая выход, чтобы избежать слишком долгого ответа. Снова добавьте > для перенаправления на файл

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

Подход №3: попросите bash выполнить задание для вас

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

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 (aka <<< "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

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

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 {}; {}"'
11
ответ дан 23 May 2018 в 16:29
  • 1
    Приятно, но он не включает команду, как это делает код Arronical. – DK Bose 22 October 2015 в 18:31
  • 2
    @DKBose Я добавлю еще один подход, который будет включать в себя команду. Пять минут – Sergiy Kolodyazhnyy 22 October 2015 в 18:36
  • 3
    @DKBose, как мой подход №2? – Sergiy Kolodyazhnyy 22 October 2015 в 18:52
  • 4
    Это умно, awk действительно очень настраиваемый маленький парень, не так ли? Скрипт выглядит удобным для нескольких других применений. – Arronical 22 October 2015 в 19:00
  • 5
    Это лучший ответ, потому что использование скрипта позволяет избежать любых побочных эффектов от аргументов, которые могут выполнять код при отображении с эхом и т. Д. - что делает второе, предназначенное, выполнение, возможно, дающим разные результаты, чем если бы команда запускалась отдельно. – Joe 30 October 2015 в 11:37
Начать script -q outputfile Выполнить команду Нажмите Ctrl-D Открыть файл 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>
6
ответ дан 23 May 2018 в 16:29

Если вы хотите расширение псевдонима (только 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
5
ответ дан 23 May 2018 в 16:29

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

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

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

chmod +x script

Запустите его следующим образом:

./script kde-window-manager > ~/Desktop/kwin-depends
4
ответ дан 23 May 2018 в 16:29
  • 1
    Преимущество такого подхода состоит в том, что вам легче повторить эту командную строку позже, если вы захотите! Вы также можете записать перенаправление в скрипт, чтобы script.sh всегда создавал файл с именем script.log с его выходом. – Gaurav 23 October 2015 в 04:21

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

Подготовка:

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

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

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

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

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

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

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
4
ответ дан 23 May 2018 в 16:29

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

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

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

3
ответ дан 23 May 2018 в 16:29
  • 1
    Я принимаю этот ответ, потому что решение более широко применимо. – DK Bose 22 October 2015 в 17:50
  • 2
    @DKBose Вам нужно будет ввести модуль дважды. Но решение со сценарием действительно универсально. – Pilot6 22 October 2015 в 19:10
  • 3
    Мне жаль, что я должен не принимать этот ответ, даже если он делает то, о чем я просил. Надеюсь, ты не против! – DK Bose 23 October 2015 в 15:44
  • 4
    Не проблема @DKBose, я знал, что это довольно неэлегантное решение, когда я отправил ответ, и выучил некоторые хорошие вещи из альтернативных ответов. – Arronical 26 October 2015 в 13:45

Вы можете просто передать команду функции, которая сначала выведет команду, а затем выдает команду (перенаправления не будут напечатаны из печатной команды намеренно, вы можете легко изменить это, удалив кавычки из команды и распечатав и $@ вместо $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
<<<"[...]": здесь строка; [...] перенаправляется на cat 's 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
2
ответ дан 23 May 2018 в 16:29
  • 1
    Почему вы печатаете только $1? И нет необходимости в eval. – terdon♦ 23 October 2015 в 14:33
  • 2
    @terdon Ну, идея заключалась в том, чтобы сохранить перенаправления из печатной команды, так как я думал, что это могло бы выглядеть лучше в случае OP. Тем не менее, если я изменю его сейчас, он будет идентичен вашему ответу. Однако да, eval не требуется, не уверен, почему я добавил его раньше. Благодарю. – kos 23 October 2015 в 14:46

Другие вопросы по тегам:

Похожие вопросы: