bashシェルスクリプトでコマンドをエコーするが、実行しない方法は?


11

コマンドをエコーでシェルスクリプトを実行するための方法があるが、実際にそれらを実行するW / Oは?

名前が変数に格納されているファイルを削除するスクリプトがあるとします。

#!/bin/bash
set -v
FN="filename"
rm -f ${FN}

追加するset -vと、実行前に次のコマンドがエコーされます。

$ ./scr.sh
FN="filename"
rm -f ${FN}

ここで、実際にファイルを削除しないこのスクリプトのフローを確認します。IOW、外部環境やファイルシステムへの影響を防ぎたい。これは可能ですか?

すべてのコマンドを1つのechoコマンドでラップすることはできますが、長いスクリプトを使用するには面倒です。


私はbashスクリプトの専門家ではありませんが、これを別のプログラミング言語で作成する場合、すべてのコマンドを配列に格納します。このように、簡単にループして、コマンドを実行するか、出力を出力する必要があります。
hugo der hungrige 2014年

回答:


8

実際にそれを行わずにスクリプトを実行する方法を確認するためにスクリプトをステップ実行する方法はありません。あなたの例では、ifステートメントやループはありません。しかし、実際のスクリプトでは、多くの場合、条件付きステートメントがたくさんあります。どのブランチが取得されるかは、シェルが前のコマンドを実行したときに何が起こったかに依存することがよくあります。コマンドが実行されない場合、シェルが生成した出力や、次の条件付き分岐や割り当てステートメントが依存する可能性のある戻りコードがどうなるかをシェルが知る方法はありません。

重要なのは、スクリプトを精査し、スクリプトを実行する前にそれが何をするのかを知りたいということであれば、それは悪い考えではありません。しかし、現実的には、それを行うための最良の方法は、lessや、viまたは類似のファイルを参照することです。

追加されました

スクリプトを開発していて、最初にスクリプトをステップスルーしてロジックをテストしたいが、バグがあったとしても実際には何のダメージも与えたくない場合、私がよく使用できる解決策は、変更のみです。をecho前面に貼り付けることにより、損害を与える可能性のあるステートメント。

これは、(a)反復する項目のリストまたは変数に設定する値の生成は、ファイルシステムを変更せずに生成できることが多く、通常は(b)通常は十分なため、典型的な実際のスクリプトで機能します。コマンドを実行した場合、成功すると想定します。


ありがとう。確かにあなたが言った理由のために方法があるとしたら私は驚きますが、とにかくそれを試してみることにしました。その理由は、ネットワーク内の多くのマシン間でファイルを移動し、リモートホストでいくつかのアクションを実行するスクリプトを開発しているためです。ファイルシステムへの変更を実際にコミットする前に、スクリプトのフローを見たいのですが。すべてのリモートマシンを
調べて

1
追加:スクリプトをステップtrap read debug実行するには、実行されたすべての行の後に読み取りを行うスクリプトを開始し、Enterキーを使用してゆっくりとステップ実行できます(これは、非常に長いスクリプトがあり、テストしたい場合に役立ちます初めて)。
netigger

8

エコーする必要があると思いますが、コマンドを変数に入れれば、オンとオフを切り替えることができます。また、コマンドは、機能にすることも、必要に応じて高度にすることもできます。

#!/bin/bash
echo 'Debug'
  D=echo
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy
echo $'\n\nLive'
  D=
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy

!$ > ./conditional.sh
Debug
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
rm -f testy
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy

Live -rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy ls: cannot access testy: No such file or directory


echo / don't-echoコマンドでは引用符が必要D=evalで、ライブ部分で使用する必要がありました。しかし、いい答えです!
Jasper

5

bashの-xオプションを使用してフローをトレースしますが、これでもコマンドは実行されます。

あなたができる最善のことは、エコーのように置くか、rmのような外部効果を持つコマンドをコメントアウトすることです。少なくとも、すべての行を変更する必要はありません。


ありがとう。私は私の質問でそのオプションについて述べましたが、それは本当に私の問題を解決しません。
ysap 2013年

すみません、すべての行をエコーするつもりだと思っていました。-xを使用すると、これがいくつかのコマンドに削減され、評価が表示されます。
parkydr 2013年

4

ドライランの特定の方法はわかりませんが、不明なスクリプトを理解するためにいくつかの予防策を使用できます。

  1. chroot環境を使用してデバッグスクリプトを実行します。サンドボックスとして機能し、メインシステムファイルの削除/変更に対する保護を提供します。
  2. 構文チェックに使用bash -n <script>ます。gnu bashマニュアルからhttps://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html

-n Read commands but do not execute them; this may be used to check a script for syntax errors. This option is ignored by interactive shells.

  1. 少なくとも一度はスクリプトを読んでください。user191016の回答で述べたように、echoステートメントをデバッグに使用できます
    • 疑わしいコードや危険な傾向のあるコードを探します。
    • たとえば、rm、/ dev / sdaに影響するコマンドなどに関連します。
  2. 常に通常のユーザーとしてスクリプトを実行するようにしてください。不明なスクリプトをrootとして実行しないください。
  3. あなたはできるエイリアス定義スクリプトの例の開始時に、対話型としてファイルを変更することができますコマンドを作るための alias rm="rm -i" alias cp="cp -i" alias mv="mv -i" sedのようなストリームエディタについて sed -iあなたは(それは詳細についてはsedは、チェックmanページのための予行演習を行い-iない場所にファイル-i修正を)コマンド全体をコピーして実行できます。実際のコマンドの直前に画面に出力を表示し、コマンドを使用してユーザー入力が続行されるのを待ちます。例 sed -i <pattern> 置き換える sed <pattern> read -p "Press any key..." sed -i <pattern>

また、緊急時にデータを復元できるように、システムにバックアップポイントを保持することを常にお勧めします。


3

するかset –nn既存のset –vコマンドに追加します。ただし、これにより、シェルはコマンドを評価せず、ifまたはも評価しwhileないため、操作の流れをよく理解できなくなる可能性があります。


ありがとう。これは良いスタートですが、あなたが言ったように、実際のフローを見ることができません-私の実際のスクリプトでは、リモートホストのリストをループしています。
ysap 2013年

3

使用したい小さな構成要素は次のとおりです。

#!/bin/sh

verbose=false
really=true

# parse arguments
while [ $# -ge 1 ]
do
  case "$1" in
    -v) verbose=true ;;
    -n) really=false; verbose=true ;;
  esac
  shift
done

doCmd() {
  if $verbose; then echo "$@"; fi
  if $really; then "$@"; fi
}

doCmd make foo
doCmd rm -rf /tmp/installdir
doCmd mkdir /tmp/installdir
doCmd whatever
doCmd blah blah

2

変更が行われないようにしたい場合は、特権を持たないユーザーとしてスクリプトを実行できます。

sudo -u nobody ./scr.sh

あなたの例では、これはFN="filename"通常通り実行されます。技術的にはコマンドrm -f ${FN}も実行しますが、ファイルを削除するために必要な権限が誰にもない場合は何も起こりません。

もちろん、これは条件付きワークフローで問題を引き起こします。rmコマンドが失敗したという事実は、スクリプトの他の部分に影響を与える可能性があります。


私たちが決して理解できないこと:なぜrootが誰としても実行する必要がないのか...
mjohnsonengr 2014

ユーザー「nobody」はOSにとって特別なものではありませんが、「nobody」のパスワードなしのsudoを許可するエントリをsudoersファイルに追加できます。
デニス

私は知らないよ。なんらかのエラーが発生したため、スクリプトが終了する前にスクリプトが終了したようです。
エドワードフォーク2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.