
お世話になります。
パイプを使わずにtee コマンドと同じように振る舞わせる方法がわかりません。
なにかよい知恵はありませんでしょうか。。。
今まで、bashスクリプトの中で
関数 | tee -a ログファイル名
という形式でログファイルを出力していたのですが
関数の中でシェル変数を書き換える必要があってパイプが使えなくなってしまいました。
リアルタイムに関数の標準出力をターミナル出力しつつ、ログファイルにも保存していきたいのですが
こういう場合、どうすればよいのでしょうか?
とりあえず
touch ログファイル名
tail -f ログファイル名 &
関数
sleep 2
kill %1
という形で、暫定的に逃げているのですが
kill したときに出力されるメッセージが消せずにかっこわるいので
できればこの方法は変更したいです。
ご教示ください。
No.2ベストアンサー
- 回答日時:
最初意味がわからなかったのですが
function func {
a=5
echo $a
}
a=0
echo $a #→ 0
func | tee -a ファイル # ファイルに「5」
echo $a #→ 上のパイプが無いと5,あると0 ←ある場合でも5にしたい
ということでよろしいでしょうか?
思いつくのは次のものです。
やりたいことと一致しないかもしれませんが。
・関数内で、teeを使う
function func {
a=5
echo $a | tee -a ファイル
}
・メインルーチンを()でサブシェルにして、全体にteeを使う
(a=0
echo $a
func
echo $a ) | tee -a ファイル
・メインルーチンを関数にして、その関数にteeを使う
function main {
a=0
echo $a
func
echo $a
}
main | tee -a ファイル
・コマンドラインでteeを使う
bash script.sh | tee -a ファイル
この回答への補足
パイプを使わずにteeをしているときと同じことをしたいというのが目的なのですが
その背景としては、作成しているスクリプトでは、
とあるディレクトリ内にあるファイルを順次読み込んで、決まった名前の関数を実行するという形になっています。(この関数にはテストが書いてあるので以下テストといいます。)
tee を利用しているのは、テストが出力した結果を画面でリアルタイムに確認できるようにするのと
あとで、確認できるようにログファイルにも同時に保存するためにtee を利用していました。
そして、このテストの結果を$PIPESTATUS で判断していたのですが、
exitコードだけでなく、テストの内部で発生したエラーの履歴をスタックしていきたいと思ったことが発端です。
なので、やりたいことを全部列挙するならば
1. 実行している関数の画面出力をリアルタイムに確認したい
2. 順次実行した関数の画面出力をログファイルに残したい
3. 実行した関数の中で発生したエラーの履歴をexitコードとともに取得したい
ということでしょうか。
んで、 3. を実現するためには パイプは使えないので tee が使えなくなり
tee が使えないと1. と 2.が機能しないということで困っていました。
teeを使っていたのは
最終的に画面とログファイルに出力結果が出ていればよいだけなので
ループの根元で一カ所だけteeするようにするのが一番無難に思えてきました。
No.4
- 回答日時:
書き換えたいシェル変数が exit ステータスの範囲なら、……
$ function some_func () {
> echo $STATUS
> return $(expr $STATUS - 1)
> }
$ export STATUS=5
$ while [ $STATUS != 0 ]; do
> some_func
> export STATUS=$?
> done | tee log.txt
5
4
3
2
1
$ cat log.txt
5
4
3
2
1
$
No.3
- 回答日時:
補足1に書かれた物レベルだと、いろいろ手はありますね。
条件に合う物を選んでください。案1:安易な方法
(
STATUS=120
test ()
{
STATUS=130
echo $STATUS #リダイレクト用と端末表示用に二回出す
echo $STATUS >&2
}
echo in:${STATUS} >&2
test
echo out:${STATUS} >&2
) >> a.log
案2:質問に書かれた方法で、killのメッセージを抑止
STATUS=120
test ()
{
STATUS=130
echo $STATUS
}
tail -f a.log &
echo in:${STATUS}
test >> a.log
echo out:${STATUS}
sleep 2
exec 2>/dev/null #メッセージを捨てる
kill %1
sleep 1 # ちょっと待つ
exec 2>/dev/tty # 元に戻す。後続処理がないなら不要
案3:パイプ内から外側の変数を書き換える方法
touch tmpfile
trap ". tmpfile" SIGUSR1 #シグナルを受けるとファイルの中身を自プロセスで実行
STATUS=120
test ()
{
STATUS=130
echo STATUS=$STATUS > tmpfile #実行して欲しいコマンドを書く
kill -SIGUSR1 $$ #書いたファイルを親プロセスに実行させる
echo $STATUS
}
echo in:${STATUS}
test | tee -a a.log
echo out:${STATUS}
最後のが応用範囲が広いですが、ファイルを使うので後始末や名前の重複の考慮が必要。例えば
WORK=/tmp/tmpfile$$
touch $WORK
trap "rm $WORK" 0 1 2 3 4 5 6 7 8 11 12 13 14 15
trap ". $WORK" SIGUSR1
STATUS=120
test ()
{
STATUS=130
echo STATUS=$STATUS > $WORK
kill -SIGUSR1 $$
echo $STATUS
}
echo in:${STATUS}
test | tee -a a.log
echo out:${STATUS}
なお、testというのはシェルの組み込みコマンドにも/usr/binにもあるので例示としても避けた方が良いです。
test については失礼しました。
何も考えず書いて予定通り動いたからそのまま貼り付けてしまいました。
ファイルを使う方法は最後の手段として考えたいと思います。
実行時には、実行単位にワークディレクトリを作成しているので後しまつは考えなくてもよいようになっています。
# むしろ、作成したファイルは一切削除しない方針で作成しています。
killメッセージの抑止については
sh -c "tail -f ログファイル名 & echo \$! > $$.tail.pid"
kill -TERM `cat $$.tail.pid`
という感じで抑止するようにしました。
No.1
- 回答日時:
うん?
「シェル変数を書き換える」ことと「パイプが使えない」こととの関係が理解できないんだけど....
この回答への補足
shの パイプは子プロセスとして実行されるため、環境を呼び出し元へ引き継ぐことができません。
あれです。
cat file | while read a; do ; done の形式でファイルを読み込みながらカウントしたのに
カウント結果がとれずはまるっていうあれです。
実際のスクリプトは配列を使っているのですが
$ sh ./a.sh
in:120
130
out:120
という出力は
----
export STATUS=120
test ()
{
export STATUS=130
echo $STATUS
}
echo in:${STATUS}
test | tee -a a.log
echo out:${STATUS}
----
というshから出力された結果です。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) Linuxについて質問です。 引数に指定されたアクセスログのファイルからアクセス数が多い順に上位3つ 1 2023/02/03 03:46
- UNIX・Linux Ubuntu22.04、nanoエディタの使い方について 2 2022/10/24 19:50
- その他(プログラミング・Web制作) Windowsのマクロプログラムで、こんなことできますか? 3 2022/06/28 14:30
- Windows 10 renameコマンドでファイル名からアンダースコアを消す方法 5 2023/04/24 13:33
- システム CSVファイルのマッピング処理の省力化 1 2022/11/24 00:01
- その他(OS) Windowsで大量の画像サイズを半自動で変更する方法 6 2023/02/17 08:45
- Excel(エクセル) Excelのテーブルについて 6 2023/07/07 08:37
- Excel(エクセル) Excel ユーザー定義で変換したセルについて 3 2023/02/04 01:25
- Excel(エクセル) エクセル関数の変わった使い方 3 2022/05/13 17:12
- C言語・C++・C# C言語初心者 ポインタについて、お助けください、、 2 2023/03/15 23:50
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
batである文字列内に特定の文字...
-
シェルで and/or の優先順位に...
-
シェルスクリプトでランダム
-
【sh】tee コマンドの代替方法
-
Shellスクリプトについて
-
sh スクリプト ipアドレス形式...
-
Cシェルで標準エラー出力への...
-
Dirコマンドでフォルダ内ファイ...
-
grepでの日本語検索
-
ファイル名についている「-」と...
-
SONYの音楽ソフト「x-アプリ」...
-
ラズパイで『’test.service’をs...
-
エクセルの表にヘンな枠が・・・
-
pingは正常なのにtracerouteで...
-
Linux環境 grepで改行コード(CR...
-
OSローダの動きが変になって...
-
rm,cpコマンドの置き換えについて
-
スクリプトのエラー「unexpecte...
-
ヒアドキュメントの動作
-
空きIPアドレスを探す方法
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
batである文字列内に特定の文字...
-
シェルスクリプトの変数の制限?
-
スクリプト中のexportコマンド...
-
シェルスクリプトでうるう年判定
-
if文について
-
sh スクリプト ipアドレス形式...
-
ファイルから文字列を読み込む...
-
bashスクリプト
-
shellスクリプトから別のshell...
-
kshでのNULLの比較
-
【sh】tee コマンドの代替方法
-
Bシェル 文字列に含まれる特...
-
sedなどで、特定の文字列からタ...
-
シェルで and/or の優先順位に...
-
VBA コンパイルエラーの解消法
-
Shellスクリプトについて
-
cshの条件式について教えてくだ...
-
このrc.localで運用しても問題...
-
【シェルスクリプト】whileルー...
-
Cシェルプログラムで、あるディ...
おすすめ情報