
結果を標準出力に出すシェルスクリプトを、">"で出力先をファイルにリダイレクトして動かすと、(時間のかかる処理の間に出力ファイルサイズを見ると)増えていくはずのファイルサイズが途中で減ることがあります。
シェルスクリプト内には、csvファイルを1行読み込んでは整形出力するループ処理のrubyスクリプトがあり、ループの中、及びループの前後に標準出力があります。
シェルスクリプト内の複数のコマンド標準出力はスクリプトが終了するまで1つの書き出しになると思っていますが、いったんクローズされて次の書き込みと扱われる場合があるのでしょうか?
No.7ベストアンサー
- 回答日時:
> 次のスクリプトtmp.shでは、standard-out-from-tmp2sh.txtにtmp2.shの2つのlsコマンドの結果が書き込まれます。
> これは違う事情なのでしょうか?
>
> (tmp.sh)
> #!/bin/bash
> ScriptName=$(basename $0)
> tmp2.sh > standard-out-from-tmp2sh.txt
>
> (tmp2.sh)
> #!/bin/bash
> ls | sed ''
> ls | sed 's/^/HI/
tmp2.sh では ls を二回実行してますよね。
対して
> (foo.sh)
> #!/bin/bash
> for i in 1 2 3 4 5 ; do
> ruby hoge.rb $i > hoge-out.txt
> done
>
> (hoge.rb)
> #!/usr/bin/env ruby
> puts ARGV[0]
hoge.rb では puts を一回実行しているだけ。
だから一つの結果しか残らない。
条件の違うものを対象にして動作が違うと言われても当たり前のこと。
試しに tmp.sh 内の tmp2.sh 実行個所をコピペして二、三回実行してみると動きの違いも分かるんじゃないの。
2つの ls の結果しか残らないよ。
それと確認雑にしていた。
No,6 に書かれてるように echo /dev/null は間違ってたね。
cat /dev/null だね。
f02e様、ありがとうございます。
「シェルスクリプトの中でコマンドAを呼び出し、コマンドAの中で上書き標準出力リダイレクトが複数行われるとファイルに追加される。
シェルスクリプトの中でコマンドAとコマンドBを呼び出して、各コマンドが同じファイルに上書き標準出力をリダイレクトすると、最後の出力だけが記録される」ということですね。
前段が理解できないです。
No.11
- 回答日時:
う~ん, 言葉の定義からやりなおしかなぁ.
例えば https://linuxjm.osdn.jp/html/GNU_bash/man1/bash. … だと,「出力リダイレクト」は「[n]>word」という形だっていってる. つまり
/bin/sh tmp2.sh > tmp-out.txt
であれば「> tmp-out.txt」の部分.
そもそも, ケースA にしても「シェルスクリプトから呼び出されたスクリプト」つまり tmp2.sh の中では標準出力についてなにもしていなくって, だからこそ tmp-out.txt に出力されている. これが
echo abc | sed '' > hoge
echo abc | sed 's/^/Hi-/' > foo
のようにさらにリダイレクトしてると, また違う動作になるんだけど, ね.
No.10
- 回答日時:
その【ケースA】~【ケースD】のうち, あなたのいう
「シェルスクリプトから呼び出されたスクリプト内での複数の標準出力リダイレクトは追記される」
にあてはまるのはどれなのでしょうか? それぞれ,
「『シェルスクリプト』から呼び出された『スクリプト』内での複数の『標準出力リダイレクト』は追記される」
の
・シェルスクリプト
・スクリプト
・標準出力リダイレクト
はどれを指しているのでしょうか?
> 「シェルスクリプトから呼び出されたスクリプト内での複数の標準出力リダイレクトは追記される」
にあてはまるのはどれなのでしょうか?
ケースA, B, Cと考えています。
> ・シェルスクリプト
> ・スクリプト
> ・標準出力リダイレクト
> はどれを指しているのでしょうか?
・シェルスクリプト 先の例での tmp.sh hoge.sh bar.hsです。
・スクリプト 先の例での tmp2.sh hoge2.sh bar2.shです。
・標準出力リダイレクト 先の例での tmp-out.txt hoge-out.txt bar-out.txtです。
No.9
- 回答日時:
> 「シェルスクリプトの中でコマンドAを呼び出し、コマンドAの中で上書き標準出力リダイレクトが複数行われるとファイルに追加される。
> シェルスクリプトの中でコマンドAとコマンドBを呼び出して、各コマンドが同じファイルに上書き標準出力をリダイレクトすると、最後の出力だけが記録される」ということですね。
> 前段が理解できないです。
もっと簡単に考えるのがいいと思うんですけどね。
「シェルスクリプトの中でコマンドAを呼び出し、コマンドAの実行結果をリダイレクトでファイルへ出力。」
それぞれ別のファイルへ書き出したいというのであれば別ですが。今回の例であればコマンド内で出力が何度行われたかは考慮する意味がありません。
あくまでそのコマンドを実行した結果得られた出力をリダイレクトしているだけですから。
そもそも ls の出力にしたって内部的に print 文を何度実行しているのか分かったものではないでしょう。
f02e様、ありがとうございます。
すっきりしませんが、「ls の出力にしたって内部的に print 文を何度実行しているのか分かったものではないでしょう」にヒントがあるように思いました。
No.8
- 回答日時:
え? ごめん,
「シェルスクリプトの中でコマンドAを呼び出し、コマンドAの中で上書き標準出力リダイレクトが複数行われるとファイルに追加される。」
がどのような挙動を意味しているのかわかんない.
具体的に「こんなふうにかくとこうなる」って説明してもらえないかな. 「ファイルに追加される」の「ファイル」がなにをさすかもわかんないし.
Tacosan様、ありがとうございます。
以下の4ケースを確認しました。
「シェルスクリプトから呼び出されたスクリプト内での複数の標準出力リダイレクトは追記される」ということですね。
【ケースA】
(tmp.sh)
/bin/sh tmp2.sh > tmp-out.txt
(tmp2.sh)
echo abc | sed ''
echo abc | sed 's/^/Hi-/'
結果
$ /bin/sh ./tmp.sh
$ cat tmp-out.txt
abc
Hi-abc
【ケースB】
(hoge.sh)
ruby hoge2.rb > hoge-out.txt
(hoge2.rb)
puts "abc"
puts "def"
結果
$ /bin/sh ./hoge.sh
$ cat hoge-out.txt
abc
def
【ケースC】
(bar.sh)
/bin/sh bar2.sh > bar-out.txt
(bar2.sh)
for 1 2 ; do
echo xy
done
結果
$ /bin/sh ./bar.sh
$ cat bar-out.txt
xy
xy
【ケースD】
(coo.sh)
for i in 1 2 ; do
ruby coo2.rb > coo-out.txt
done
(coo2.rb)
puts "gh"
結果
$ /bin/sh ./coo.sh
$ cat coo-out.txt
gh
No.6
- 回答日時:
echo /dev/null > hoge-out.txt
だと「/dev/null」という 1行からなる hoge-out.txt になりますね>#5. それを意図してるならいいけど, ファイルの大きさを 0 にするなら
cat /dev/null > hoge-out.txt
: > hoge-out.txt
のどちらかでしょう.
あるいは, for 全体に対してリダイレクトすることもできます (ただし意図しない結果になることもある).
あと「実行中のスクリプトの標準出力が閉じられる」という点については, foo.sh を実行中に foo.sh の標準出力がと辞されることは*自分で閉じる*のでなければ限り発生しません. 一般にあるプロセスがオープンしたファイルは
・そのプロセスで明示的にクローズする
・そのプロセスが終了する
のどちらかによってクローズされます.
No.5
- 回答日時:
> どういう場合に、実行中のスクリプトの標準出力が閉じられるのでしょうか?
シェルスクリプトだからね、各行の実行単位で必ずクローズされる。
これは ”>” でも ”>>” でもどちらを使用しても同じこと。
ただ、”>” は実行毎にファイルの先頭から記録するのに対し、”>>” は実行毎にファイルの終端から記録していくという動作の違いがあるだけ。
捕捉にあるシェルで言うなら、1,2,3,4,5 それぞれでファイルの先頭から記録してるんだから最終的に5の実行結果しか残らない。
すべて残すなら、
ruby hoge.rb $i >> hoge-out.txt
とするか、
ruby hoge.rb $i > hoge$i-out.txt
とでもするべき。
すべて ”>>” で記録するならシェルの先頭で、
echo /dev/null > hoge-out.txt
と書いておけばシェルの実行毎にログの内容を新しく記録しなおせる。
上記 echo を実行しなければ ”>>” ですべて記録するとシェル実行毎にログが肥大化していく。
f02e様、詳しい解説をありがとうございます。たいへん勉強になります。
No.4回答のお礼にも書きましたが、No.1回答のお礼に書き込んだケースとの違いがわかりません。
> 次のスクリプトtmp.shでは、standard-out-from-tmp2sh.txtにtmp2.shの2つのlsコマンドの結果が書き込まれます。
> これは違う事情なのでしょうか?
>
> (tmp.sh)
> #!/bin/bash
> ScriptName=$(basename $0)
> tmp2.sh > standard-out-from-tmp2sh.txt
>
> (tmp2.sh)
> #!/bin/bash
> ls | sed ''
> ls | sed 's/^/HI/
No.4
- 回答日時:
いや, そのスクリプトなら当然そうなりますよ.
ruby hoge.rb $i > hoge-out.txt
というコマンドを, i を 1 から 5 まで変えながら実行するんだよ. もっと端的にいえば, i を除けば
ruby hoge.rb 1 > hoge-out.txt
ruby hoge.rb 2 > hoge-out.txt
ruby hoge.rb 3 > hoge-out.txt
ruby hoge.rb 4 > hoge-out.txt
ruby hoge.rb 5 > hoge-out.txt
と同じことをやってるんだもん.
Tacosan様、ありがとうございます。
No.1回答のお礼に書き込んだケースとの違いがわかりません。
> 次のスクリプトtmp.shでは、standard-out-from-tmp2sh.txtにtmp2.shの2つのlsコマンドの結果が書き込まれます。
> これは違う事情なのでしょうか?
>
> (tmp.sh)
> #!/bin/bash
> ScriptName=$(basename $0)
> tmp2.sh > standard-out-from-tmp2sh.txt
>
> (tmp2.sh)
> #!/bin/bash
> ls | sed ''
> ls | sed 's/^/HI/'
No.3
- 回答日時:
たとえば
hoge.sh > foo.txt
という形であれば, hoge.sh 中の標準出力は foo.txt に書き出されます. この処理は「ファイルディスクリプタ 1 が foo.txt を指す」ことで実現し, hoge.sh が動いている間 foo.txt はオープンしっぱなしになります (hoge.sh が終了するときにクローズされる).
ただし, あたりまえですが
・hoge.sh の中で foo.txt をいじる
・他のプロセスで foo.txt をオープンする
など, 競合する状況が発生していたらどうなるかはわかりません.
「ファイルサイズが途中で減る」ときに, そのファイルの中身がどうなっているかがわかればもうちょっとなんか書ける... かなぁ.
Tacosan様、ありがとうございます。
やはり、「hoge.sh が動いている間 foo.txt はオープンしっぱなしになります」ですね。
動かしているスクリプトのどのタイミングでファイルサイズが減っているのかわからないので、「そのファイルの中身がどうなっているか」をお示しできません。
しばらく自分で調べます。
(リダイレクトを ">" から ">>" に変更して終わりそう)
No.2
- 回答日時:
ごめんなさい。
Linuxは方言がきついので自分にはそのスクリプトに使われているコマンド(のオプション)を理解できない。
(コマンドリファレンスやらセルフドキュメントがないと自分は能無しです)
ただ、繰り返し ”tmp.sh” を呼び出すなら、都度 ”standard-out-from-tmp2sh.txt” ファイルが上書きされるということは分かります。
銀鱗様、ありがとうございます。
繰り返しですが、tmp.sh の中でtmp2 > file.txt を実行し、
tmp2の中で標準出力を2回出力したら、file.txtにすべて記録されます。
2つ目の出力だけでなく、すべて記録されるのはなぜでしょうか。
外部コマンドの方がよいかと思い、tmp2の中で "ls | sed" "ls | sed 's/^/HI/'"としましたが、これは
echo abc
echo def
としても同じことと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# プログラミングの問題です。至急教えてください。 /***から***/の部分をプログラミングにしてほし 1 2022/10/13 11:48
- UNIX・Linux Linuxについて質問です。 シェルスクリプト名をfind.shとして、以下の条件をすべて満たすファ 1 2023/02/03 03:50
- その他(プログラミング・Web制作) Linuxについて質問です。 引数に指定されたアクセスログのファイルからアクセス数が多い順に上位3つ 1 2023/02/03 03:46
- Java Java 年数計算 3 2023/01/28 10:52
- その他(プログラミング・Web制作) python OpenPyXLを使って出力結果をエクセルに書き込み 2 2022/06/04 19:46
- その他(AV機器・カメラ) モバイルバッテリー(USB出力)でラジオを動かす方法 7 2022/05/31 11:17
- 物理学 流体力学の勉強方法 2 2023/04/25 23:18
- Visual Basic(VBA) vbaのループ処理について 6 2022/05/06 15:35
- Java Javaの問題なのですが、 永久ループを使って以下に従って数値を出力するプログラムを作成する。 ・1 3 2023/06/06 18:43
- C言語・C++・C# C言語について。 7 2023/01/26 16:42
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Core 2 Duo の古いパソコンに最...
-
LinuxでWine使うとどのくらいWi...
-
ubuntu(linux)のシャットダウン...
-
CentOSが起動時にフリーズ
-
ubuntuのシャットダウンが進ま...
-
ubuntu 24 へのCanon 複合機ス...
-
apacheでリバースプロキシを設...
-
tarで纏める際に、複数場外した...
-
ubuntuで デイスク/deb/loopと...
-
私のパソコンでVirtualBoxは使...
-
partedで対象デバイスを間違え...
-
Fedoraのupgradeで、libruby.so...
-
次のif文について意味を教えて...
-
ユーザ名usr1でcentos(192.168....
-
至急です。kubuntu24.04ltsをUS...
-
linuxのIMEの件
-
WineのRufusでデバイスを検知す...
-
LinuxのノートパソコンでDVDコ...
-
windows10を使っています。 wsl...
-
Linux のシェルスクリプトの強...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
LinuxでWine使うとどのくらいWi...
-
Core 2 Duo の古いパソコンに最...
-
Linux のシェルスクリプトの強...
-
ubuntu(linux)のシャットダウン...
-
bashでシングルクォート内の変...
-
ubuntuで デイスク/deb/loopと...
-
apacheでリバースプロキシを設...
-
CentOSが起動時にフリーズ
-
ubuntuのシャットダウンが進ま...
-
ubuntu が起動しない。
-
Windowsのローカルディレクトリ...
-
Ububtuでファイル共有できない...
-
Ubuntu on Xorgのログインについて
-
ログにserver reached MaxReque...
-
「/var/log」内のログの削除の...
-
ubuntu 24 へのCanon 複合機ス...
-
ssl_request_logの必要性について
-
私のパソコンでVirtualBoxは使...
-
WineのRufusでデバイスを検知す...
-
LinuxのノートパソコンでDVDコ...
おすすめ情報
問題としているスクリプトの構造を単純化したものとして、次のスクリプトを走らせると
出力ファイルには最後に実行された結果しか記録されていませんでした。
hoge.rb出力リダイレクトを ">>" にするとすべて記録されていました。
どういう場合に、実行中のスクリプトの標準出力が閉じられるのでしょうか?
(foo.sh)
#!/bin/bash
for i in 1 2 3 4 5 ; do
ruby hoge.rb $i > hoge-out.txt
done
(hoge.rb)
#!/usr/bin/env ruby
puts ARGV[0]