19

Sorry for the confusing title!

Suppose I run

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

I'll get a file named "kwin-depends" in my Desktop folder.

Is there some trick to include the command I issued as part of the file, preferably at the start of the file?

So, at least in 14.04 LTS, the first few lines would look like this:

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

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

Instead of just like this:

kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
DK Bose
  • 44,553

9 Answers9

19

I would just use a simple function. Add this to your ~/.bashrc file:

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

Now, whenever you want to run a command and print it, you can do:

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

The above produces this file:

$ 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
terdon
  • 104,119
11

Most minimalistic - approach #4 and #3, both could be converted into function; #2 my favorite - awk. #1 uses script command - very versatile tool, useful for recording command line in general; applicable anywhere, for whatever you want to record.

Approach #1: There is a /usr/bin/script command ( which comes with ubuntu by default ) for recording command-line output, which captures everything , along with the prompt and command. To just save one command and its output to specific file, use -c flag and specify output file. Example

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秒

Approach #2: awk hackery

Awk has system() function which allows you running shell commands from awk script or command. The output will show up on the screen , command first, output next. To redirect what you see to a file use > operator.

That can be done in two ways - ask user to input stuff from stdin or as command line argument. First one is easier to achieve, hence posting that.

(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) Command line args version; not including output to avoid making answer too long. Again, append > to redirect to file

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

Approach #3: ask bash to do the job for you

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

Redirect to file with > operator:

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

Approach #4:(my second favorite)

Inspired by ByteCommander's post; we can use read and then run necessary commands in subshell

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

Sample run:

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

Approach #5:

Use echo or here string (aka <<< "string" ) to provide arguments to sh -c through 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

And if you want , you can use this same trick with an alias:

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

You can do:

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

Same thing using echo instead of Here strings (<<<):

echo 'apt-cache depends kde-window-manager' | tee file.txt | bash >>file.txt
  • tee will write to STDOUT and also to the file file.txt

  • The STDOUT of tee i.e. apt-cache depends kde-window-manager will be fed to bash to run the command and append the STDOUT to file.txt.

Example:

$ 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>
heemayl
  • 93,925
7
  1. Start script -q outputfile
  2. Execute your command
  3. Press Ctrl-D
  4. Open the file outputfile

Example

Start script

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

Start your command

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

Press Ctrl-D

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

Show your command and output

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

and you will see something like this

[aboettger:~/tmp] % apt-cache depends kde-window-manager
<kde-window-manager>
A.B.
  • 92,125
5

If you want alias expansion (bash only) you can do it this way :

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 $@
}

You can now run

runcmd acd leafpad > out
4

There may be an easier way, but you can do it by a script:

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

Create a file script with this content in your Home folder and give execution permission

chmod +x script

Run it this way:

./script kde-window-manager > ~/Desktop/kwin-depends
Pilot6
  • 92,041
4

Extremely simple solution using a one-line Bash function

Preparation:

This approach uses a custom bash function to provide the desired functionality. You define it by executing the following line in your terminal session. note that you may chose any valid bash variable name instead of runandlog:

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

This however only persists for the current Bash session, that means after closing the terminal window, the function will be gone.
If you tried and liked it though, you can make it always available by editing your ~/.bashrc file and appending this line to the end of it.

How to use:

After having defined the function, you may use it to run commands while logging both the command itself and its output to a file. You could even add more information like the user who executed it, which I already included into the function, or exact time it was ran. Feature-requests in comments are welcome! :)

The syntax is simple:

runandlog LOGFILENAME YOUR-COMMAND-WITH-ARGUMENTS

Example:

An example session as user bytecommander, operating from the home directory could look like this:

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

Which will result in a new file mylogfile (if it already exists, the function will append the output to it!) in the current directory with the content:

[bytecommander] $ fortune 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos
Byte Commander
  • 110,243
3

A fairly unclever but functional trick would be:

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

Ugly, but it works!

Arronical
  • 20,241
2

You could simply pass the command to a function which will print the command first and the command's output afterwards (the redirections are kept out of the printed command intentionally, you may easily change this by removing the quotes from the command and by printing and running $@ instead of $1 in the function):

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

bar

To add the command afterwards you could run this command, which will insert the last command run at the top of a file:

<<<"$(<foo)" cat <(history 2 | sed -n '1s/  [0-9][0-9]*  \(.*\)/\1\n/p') - >foo
  • <<<"[...]": here string; [...] is redirected to cat's stdin;
  • $(<foo): command substitution; it's replaced with "foo"'s content;
  • cat [...] - >foo: concatenates stdin to [...] and outputs to "foo";
  • <([...]): process substitution: it's replaced with a file descriptor containing the output of [...];
  • history 2 | sed -n '1s/ [0-9][0-9]* \(.*\)/\1\n/p': outputs the last two commands, removes two spaces followed by one or more digits followed by two spaces from the first line and prints it;
$ 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
kos
  • 41,268