Bagaimana cara mengulang perintah shell saat dijalankan


912

Dalam skrip shell, bagaimana cara mengulang semua perintah shell yang dipanggil dan memperluas nama variabel apa pun?

Misalnya, diberi baris berikut:

ls $DIRNAME

Saya ingin skrip untuk menjalankan perintah dan menampilkan yang berikut ini

ls /full/path/to/some/dir

Tujuannya adalah untuk menyimpan log dari semua perintah shell yang dipanggil dan argumennya. Apakah mungkin ada cara yang lebih baik untuk menghasilkan log seperti itu?

Jawaban:


1043

set -xatau set -o xtracememperluas variabel dan mencetak tanda + kecil sebelum baris.

set -vatau set -o verbosetidak memperluas variabel sebelum dicetak.

Gunakan set +xdan set +vuntuk mematikan pengaturan di atas.

Pada baris pertama skrip, seseorang dapat menempatkan #!/bin/sh -x(atau -v) memiliki efek yang sama dengan set -x(atau -v) nanti dalam skrip.

Di atas juga berfungsi dengan /bin/sh.

Lihat wiki bash-hacker pada setatribut , dan pada debugging .

$ cat shl
#!/bin/bash                                                                     

DIR=/tmp/so
ls $DIR

$ bash -x shl 
+ DIR=/tmp/so
+ ls /tmp/so
$

7
Jika Anda juga ingin melihat baris bernomor mana yang dieksekusi, lihat stackoverflow.com/a/17805088/1729501
user13107

3
bagaimana jika saya ingin mewarnai perintah ketika gema untuk membedakan perintah dan hasil keluarannya?
Lewis Chan

11
Bagaimana jika saya ingin menyanyikan setiap perintah melalui synthesizer ucapan seperti vocaloid ketika bergema, sehingga saya dapat mendengar apa yang dilakukannya dari kejauhan dan juga menikmati musik? Mungkin dengan suara yang berbeda untuk input dan output.
ADJenks

(ABS memiliki sejarah panjang yang tidak responsif terhadap permintaan agar mereka memperbaiki contoh praktik buruk, sampai mendorong anggota masyarakat yang sudah lama untuk menciptakan sumber daya yang bersaing; memindahkan tautan ke wiki bash-hacker - wiki Wooledge atau manual bash resmi juga akan menjadi sumber yang lebih baik).
Charles Duffy

317

set -x akan memberi Anda apa yang Anda inginkan.

Berikut ini contoh skrip shell untuk diperagakan:

#!/bin/bash
set -x #echo on

ls $PWD

Ini memperluas semua variabel dan mencetak perintah lengkap sebelum output dari perintah.

Keluaran:

+ ls /home/user/
file1.txt file2.txt

21
Menggunakan kata "verbose" seperti itu tidak menghasilkan apa-apa. Anda dapat melakukan set -o verboseatau set -v(hanya "verbose") atau set -o xtraceatau set -x(hanya "xtrace") atau set -xv(keduanya) atau set -o xtrace -o verbose(keduanya).
Dijeda sampai pemberitahuan lebih lanjut.

ini bekerja dengan baik, tetapi perlu diketahui bahwa "verbose" menimpa $ 1
JasonS

90

Saya menggunakan fungsi untuk menggema dan menjalankan perintah:

#!/bin/bash
# Function to display commands
exe() { echo "\$ $@" ; "$@" ; }

exe echo hello world

Output yang mana

$ echo hello world
hello world

Untuk pipa perintah yang lebih rumit, dll., Anda dapat menggunakan eval:

#!/bin/bash
# Function to display commands
exe() { echo "\$ ${@/eval/}" ; "$@" ; }

exe eval "echo 'Hello, World!' | cut -d ' ' -f1"

Output yang mana

$  echo 'Hello, World!' | cut -d ' ' -f1
Hello

Tidak banyak suara untuk jawaban ini. Apakah ada alasan mengapa itu ide yang buruk? Bekerja untuk saya, dan tampaknya persis seperti apa yang saya cari ...
fru1tbat

1
Ini adalah jawaban terbaik jika Anda tidak ingin setiap perintah dicetak. Ini menghindari ++ set +xoutput ketika dimatikan, serta terlihat lebih bersih. Hanya untuk satu atau dua pernyataan, jawaban bhassel menggunakan subkulit adalah yang paling nyaman.
Brent Faust

Ini yang saya cari! Tidak set +x, itu mempengaruhi semua perintah, yang terlalu banyak!
Hlung

11
Kelemahan utama dari hal ini adalah bahwa output kehilangan informasi penawaran. Anda tidak dapat membedakan antara cp "foo bar" bazdan cp foo "bar baz", misalnya. Jadi, bagus untuk menampilkan informasi kemajuan kepada pengguna; apalagi untuk debugging output atau merekam perintah yang direproduksi. Kasus penggunaan berbeda. Di zsh, Anda dapat menyimpan kutipan dengan :qpengubah:exe() { echo '$' "${@:q}" ; "$@" ; }
Andrew Janke

2
Saya tidak suka jawaban ini. Ada banyak kasus tepi di mana apa yang Anda lihat bukan apa yang Anda dapatkan (terutama dengan spasi putih, tanda kutip, karakter yang lolos, penggantian variabel / ekspresi, dll), jadi jangan menempelkan perintah yang di-echo ke terminal secara membabi buta dan menganggapnya akan berjalan cara yang sama. Juga, teknik kedua hanya hack, dan akan menghapus contoh kata lain evaldari perintah Anda. Jadi jangan berharap itu berfungsi dengan baik exe eval "echo 'eval world'"!
mwfearnley

88

Anda juga dapat mengaktifkan ini untuk baris tertentu dalam skrip Anda dengan membungkusnya set -xdan set +x, misalnya,

#!/bin/bash
...
if [[ ! -e $OUT_FILE ]];
then
   echo "grabbing $URL"
   set -x
   curl --fail --noproxy $SERV -s -S $URL -o $OUT_FILE
   set +x
fi

54

jawaban shuckc untuk menggemakan baris pilih memiliki beberapa kelemahan: Anda berakhir dengan set +xperintah berikut juga digemakan, dan Anda kehilangan kemampuan untuk menguji kode keluar dengan $?karena ditimpa oleh set +x.

Opsi lain adalah menjalankan perintah dalam sebuah subkulit:

echo "getting URL..."
( set -x ; curl -s --fail $URL -o $OUTFILE )

if [ $? -eq 0 ] ; then
    echo "curl failed"
    exit 1
fi

yang akan memberi Anda output seperti:

getting URL...
+ curl -s --fail http://example.com/missing -o /tmp/example
curl failed

Ini menimbulkan biaya tambahan untuk membuat subkulit baru untuk perintah.


7
Cara yang bagus untuk menghindari ++ set +xoutput.
Brent Faust

3
Bahkan lebih baik: ganti if [ $? -eq 0 ]dengan if (set -x; COMMAND).
Amedee Van Gasse

35

Opsi lain adalah meletakkan "-x" di bagian atas skrip Anda alih-alih pada baris perintah:

$ cat ./server
#!/bin/bash -x
ssh user@server

$ ./server
+ ssh user@server
user@server's password: ^C
$

Perhatikan bahwa ini tampaknya tidak berfungsi sama persis antara ./myScriptdan bash myScript. Masih bagus untuk ditunjukkan, terima kasih.
altendky

27

Menurut TLDP 's Bash Panduan untuk Pemula: Bab 2. Menulis dan debugging skrip :

2.3.1. Debugging pada seluruh skrip

$ bash -x script1.sh

...

Sekarang ada debugger lengkap untuk Bash, tersedia di SourceForge . Fitur-fitur debug ini tersedia di sebagian besar versi modern Bash, mulai dari 3.x.

2.3.2. Debugging pada bagian skrip

set -x            # Activate debugging from here
w
set +x            # Stop debugging from here

...

Tabel 2-1. Tinjauan umum tentang mengatur opsi debugging

    Short  | Long notation | Result
    -------+---------------+--------------------------------------------------------------
    set -f | set -o noglob | Disable file name generation using metacharacters (globbing).
    set -v | set -o verbose| Prints shell input lines as they are read.
    set -x | set -o xtrace | Print command traces before executing command.

...

Atau, mode ini dapat ditentukan dalam skrip itu sendiri, dengan menambahkan opsi yang diinginkan ke deklarasi shell baris pertama. Opsi dapat dikombinasikan, seperti biasanya dengan perintah UNIX:

#!/bin/bash -xv

18

Ketik "bash -x" pada baris perintah sebelum nama skrip Bash. Misalnya, untuk menjalankan foo.sh, ketikkan:

bash -x foo.sh

11

Anda dapat menjalankan skrip Bash dalam mode debug dengan -xopsi .

Ini akan mengulangi semua perintah.

bash -x example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

Anda juga dapat menyimpan opsi -x dalam skrip . Cukup tentukan -xopsi di shebang.

######## example_script.sh ###################
#!/bin/bash -x

cd /home/user
mv text.txt mytext.txt

##############################################

./example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

2
Juga bash -vxakan melakukan hal yang sama tetapi tanpa interpolasi variabel
loa_in_

4

Untuk zsh, gema

 setopt VERBOSE

Dan untuk debugging,

 setopt XTRACE

2

Untuk cshdan tcsh, Anda bisa set verboseatauset echo (atau Anda bahkan dapat mengatur keduanya, tetapi sebagian besar waktu dapat mengakibatkan duplikasi).

Itu verbose pilihan mencetak cukup banyak shell ekspresi yang tepat yang Anda ketik.

The echopilihan lebih menunjukkan apa yang akan dijalankan melalui pemijahan.


http://www.tcsh.org/tcsh.html/Special_shell_variables.html#verbose

http://www.tcsh.org/tcsh.html/Special_shell_variables.html#echo


Special shell variables

verbose If set, causes the words of each command to be printed, after history substitution (if any). Set by the -v command line option.

echo If set, each command with its arguments is echoed just before it is executed. For non-builtin commands all expansions occur before echoing. Builtin commands are echoed before command and filename substitution, because these substitutions are then done selectively. Set by the -x command line option.


1
$ cat exampleScript.sh
#!/bin/bash
name="karthik";
echo $name;

bash -x exampleScript.sh

Output adalah sebagai berikut:

masukkan deskripsi gambar di sini


Apa definisi warna untuk terminal Anda (RGB, numerik)?
Peter Mortensen

1

Untuk memungkinkan perintah majemuk untuk digaungkan, saya menggunakan fungsi evalplus Soth exeuntuk menggema dan menjalankan perintah. Ini berguna untuk perintah pipa yang jika tidak hanya akan menampilkan tidak ada atau hanya bagian awal dari perintah pipa.

Tanpa eval:

exe() { echo "\$ $@" ; "$@" ; }
exe ls -F | grep *.txt

Output:

$
file.txt

Dengan eval:

exe() { echo "\$ $@" ; "$@" ; }
exe eval 'ls -F | grep *.txt'

Output yang mana

$ exe eval 'ls -F | grep *.txt'
file.txt
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.