Czy dołączyć polecenie do pliku wyjściowego?

17

Przepraszam za mylący tytuł!

Załóżmy, że biegnę

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

W folderze pulpitu otrzymam plik o nazwie „kwin-depends”.

Czy jest jakaś sztuczka, aby dołączyć polecenie, które wydałem jako część pliku, najlepiej na początku pliku?

Tak więc, przynajmniej w 14.04 LTS, kilka pierwszych linii wyglądałoby tak:

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

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

Zamiast tego:

kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
DK Bose
źródło
3
Ponieważ istnieje obecnie wiele innych dobrych i elastycznych rozwiązań, możesz rozważyć odrzucenie odpowiedzi, która sugeruje ręczne wpisanie polecenia do pliku przez wpisanie go dwukrotnie i zaakceptowanie jednego z uniwersalnych rozwiązań.
Bajt Dowódca

Odpowiedzi:

18

Chciałbym po prostu użyć prostej funkcji. Dodaj to do swojego ~/.bashrcpliku:

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

Teraz, gdy chcesz uruchomić polecenie i wydrukować je, możesz:

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

Powyżej tworzy ten plik:

$ 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
źródło
Nie chcę tutaj przesuwać słupków bramki, ale czy istnieje sposób, aby twój kod akceptował również aliasy? Na przykład, jeśli alias apt-cache dependsdo acdotrzymuję „Brak polecenia«ACD»znaleziony, miałaś na myśli ...” gdy biegnęruncom acd leafpad > out .
DK Bose,
Aliasy @DKBose są zdefiniowane w pliku .bashrc, a nie w powłoce, a funkcje wywołują tylko pliki binarne znajdujące się w zmiennej $ PATH. Ale możesz zrobić prostą sztuczkę. Na przykład lsjest aliasowany ls --color=auto' w rzeczywistości. Co można zrobić (o ile nie ma apostrofów lub cudzysłowów w swoim pseudonimem), to jest: $ terdonsFunction $(alias ls | awk -F '=' '{$1="";print}'| tr "'" " ") .
Sergiy Kolodyazhnyy
LUB zmień polecenie w zmienną. Tak jak pokazałem wcześniej w mojej odpowiedzi. MYCOMMAND="apt-cache depends"; terdonsFunction $MYCOMMAND leafpad > out.txt
Sergiy Kolodyazhnyy
@Serg, zobacz odpowiedź GARCINA Davida: askubuntu.com/a/688936/248158
DK Bose
To jest „oczywista” odpowiedź i działa świetnie, chyba że którykolwiek z argumentów dotyczy kodu, który wykonuje się i ma skutki uboczne, które mogą się kumulować. Jest to przypadek skrajny, więc nie występowałby zbyt często.
Joe
11

Możesz to zrobić:

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

Tej samej rzeczy używa się echozamiast ciągów Here ( <<<):

echo 'apt-cache depends kde-window-manager' | tee file.txt | bash >>file.txt
  • tee napisze do STDOUT, a także do pliku file.txt

  • STDOUT teeie apt-cache depends kde-window-managerzostanie przekazany bashdo uruchomienia polecenia i dołączony do STDOUT file.txt.

Przykład:

$ 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
źródło
1
Świetna odpowiedź! Prosto i na temat! Próbowałem z jednym, teeale mój ciągle zawodził. Dobra robota! +1
Terrance
@Seth Zastanawiałem się również nad grą z deskryptorami plików, ale teewydaje się
fajne
11

Najbardziej minimalistyczne - podejście nr 4 i nr 3, oba można przekształcić w funkcje; # 2 mój ulubiony -awk . # 1 używa scriptpolecenia - bardzo wszechstronnego narzędzia, przydatnego do nagrywania wiersza poleceń w ogóle; ma zastosowanie w dowolnym miejscu i do wszystkiego, co chcesz nagrać.

Podejście nr 1: istnieje/usr/bin/script polecenie (domyślnie dostarczane z Ubuntu) do nagrywania danych wyjściowych z wiersza poleceń, które przechwytuje wszystko, wraz z monitem i poleceniem. Aby zapisać tylko jedno polecenie i jego wynik w określonym pliku, użyj -cflagi i określ plik wyjściowy. Przykład

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

Podejście nr 2: hackery awk

Awk ma system()funkcję, która pozwala na uruchamianie poleceń powłoki zawk skryptu lub polecenia . Wyjście pojawi się na ekranie, najpierw polecenie, następnie następne. Aby przekierować to, co widzisz, do >operatora pliku, użyj .

Można to zrobić na dwa sposoby - poproś użytkownika o wprowadzenie danych ze standardowego wejścia lub argumentu wiersza poleceń. Pierwszy jest łatwiejszy do osiągnięcia, stąd opublikowanie go.

(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) Wersja argumentów linii poleceń; bez uwzględnienia danych wyjściowych, aby uniknąć zbyt długich odpowiedzi. Ponownie dołącz >do przekierowania do pliku

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

Podejście nr 3: poproś bash o wykonanie pracy za ciebie

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

Przekieruj do pliku z >operatorem:

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

Podejście 4: (mój drugi ulubiony)

Zainspirowany postem ByteCommander; możemy użyć, reada następnie uruchomić niezbędne polecenia w podpowłoce

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

Przykładowy przebieg:

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

Podejście nr 5:

Użyj echolub here string(aka <<< "string"), aby podać argumenty sh -cpoprzezxargs

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

A jeśli chcesz, możesz użyć tej samej sztuczki z aliasem:

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 {}; {}"'
Sergiy Kolodyazhnyy
źródło
Fajnie, ale nie zawiera polecenia takiego jak kod Arronical.
DK Bose,
@DKBose Dodam inne podejście, które będzie zawierać polecenie. Pięć minut
Sergiy Kolodyazhnyy
@DKBose, jak tam moje podejście # 2?
Sergiy Kolodyazhnyy
To sprytne, awknaprawdę to bardzo konfigurowalny koleś, prawda? `skrypt wygląda również na przydatny do kilku innych zastosowań.
Arroniczny
1
Jest to najlepsza odpowiedź, ponieważ użycie skryptu pozwala uniknąć skutków ubocznych argumentów, które mogłyby spowodować wykonanie kodu po wyświetleniu go za pomocą echa itp. - dzięki temu drugie, zamierzone wykonanie może dać inne wyniki niż w przypadku osobnego uruchomienia polecenia.
Joe
6
  1. Początek script -q outputfile
  2. Wykonaj polecenie
  3. Naciśnij Ctrl-D
  4. Otwórz plik outputfile

Przykład

Początek script

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

Uruchom polecenie

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

Naciśnij Ctrl-D

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

Pokaż swoje polecenie i dane wyjściowe

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

i zobaczysz coś takiego

[aboettger:~/tmp] % apt-cache depends kde-window-manager
<kde-window-manager>
AB
źródło
5

Jeśli chcesz rozwinąć alias (tylko bash), możesz to zrobić w ten sposób:

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

Możesz teraz biegać

runcmd acd leafpad > out
GARCIN David
źródło
4

Może być łatwiejszy sposób, ale możesz to zrobić za pomocą skryptu:

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

Utwórz plik scriptz tą zawartością w folderze domowym i zezwól na wykonanie

chmod +x script

Uruchom to w ten sposób:

./script kde-window-manager > ~/Desktop/kwin-depends
Pilot 6
źródło
Takie podejście ma tę zaletę, że ułatwia powtórzenie tego wiersza poleceń, jeśli chcesz! Możesz również zapisać przekierowanie w skrypcie, aby script.shzawsze tworzył plik o nazwie script.logwyjściowej.
Gaurav
4

Niezwykle proste rozwiązanie wykorzystujące jednowierszową funkcję Bash

Przygotowanie:

To podejście wykorzystuje niestandardową funkcję bash, aby zapewnić pożądaną funkcjonalność. Zdefiniujesz go, wykonując następujący wiersz w sesji terminalu. pamiętaj, że możesz wybrać dowolną prawidłową nazwę zmiennej bash zamiast runandlog:

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

To pozostaje jednak tylko dla bieżącej sesji Bash, co oznacza, że ​​po zamknięciu okna terminala funkcja zniknie.
Jeśli jednak próbowałeś go lubić, możesz go zawsze udostępnić, edytując ~/.bashrcplik i dołączając ten wiersz na końcu.

Jak używać:

Po zdefiniowaniu funkcji możesz użyć jej do uruchamiania poleceń podczas rejestrowania zarówno samego polecenia, jak i jego wyniku w pliku. Możesz nawet dodać więcej informacji, takich jak użytkownik, który ją wykonał, które już zawarłem w funkcji, lub dokładny czas jej uruchomienia. Żądania funkcji w komentarzach są mile widziane! :)

Składnia jest prosta:

runandlog LOGFILENAME YOUR-COMMAND-WITH-ARGUMENTS

Przykład:

Przykładowa sesja jako użytkownik bytecommanderdziałająca z katalogu domowego może wyglądać następująco:

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

Co spowoduje powstanie nowego pliku mylogfile (jeśli już istnieje, funkcja doda do niego dane wyjściowe!) W bieżącym katalogu z zawartością:

[bytecommander] $ fortune 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos
Bajt Dowódca
źródło
3

Dość niepewną, ale funkcjonalną sztuczką byłoby:

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

Brzydkie, ale działa!

Arroniczny
źródło
Akceptuję tę odpowiedź, ponieważ rozwiązanie ma szersze zastosowanie.
DK Bose
@DKBose Będziesz musiał wpisać moduł dwukrotnie. Ale rozwiązanie ze skryptem jest naprawdę uniwersalne.
Pilot6
Przepraszam, że muszę nie zaakceptować tej odpowiedzi, mimo że robi to, o co prosiłem. Mam nadzieję, że nie masz nic przeciwko!
DK Bose,
2
Nie stanowi problemu @DKBose, wiedziałem, że było to dość nieeleganckie rozwiązanie, gdy przesłałem odpowiedź, i nauczyłem się kilku dobrych rzeczy z zamieszczonych alternatywnych odpowiedzi.
Arroniczny
2

Możesz po prostu przekazać polecenie do funkcji, która najpierw wydrukuje polecenie, a następnie jego wynik (przekierowania są celowo ukryte przed wydrukowanym poleceniem, możesz to łatwo zmienić, usuwając cudzysłowy z polecenia i drukując i uruchamiając je $@zamiast tego o $1w funkcji)

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

bar

Aby dodać polecenie później, możesz uruchomić to polecenie, które wstawi ostatnie uruchomienie polecenia u góry pliku:

<<<"$(<foo)" cat <(history 2 | sed -n '1s/  [0-9][0-9]*  \(.*\)/\1\n/p') - >foo
  • <<<"[...]": tutaj ciąg; [...]jest przekierowany na cat's stdin;
  • $(<foo): podstawienie polecenia; zostało zastąpione treścią „foo”;
  • cat [...] - >foo: Łączy stdindo [...]i wyjścia z „foo”;
  • <([...]): podstawienie procesu: jest zastąpione deskryptorem pliku zawierającym dane wyjściowe [...];
  • history 2 | sed -n '1s/ [0-9][0-9]* \(.*\)/\1\n/p': wypisuje dwie ostatnie komendy, usuwa dwie spacje, po których następuje jedna lub więcej cyfr, a następnie dwie spacje z pierwszego wiersza i wypisuje je;
$ 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
źródło
Dlaczego tylko drukujesz $1? I nie ma takiej potrzeby eval.
terdon
@terdon Cóż, pomysł polegał na tym, aby przekierowania nie wyświetlały się w poleceniu drukowanym, ponieważ myślałem, że w przypadku OP mogłoby to wyglądać ładniej. Niemniej jednak, jeśli zmienię to teraz, byłoby to identyczne z odpowiedzią. Jednak tak, evalnie jest potrzebne, nie jestem pewien, dlaczego dodałem go wcześniej. Dzięki.
Kos