2016-08-09 5 views
0

sed -eを使用して設定ファイルのいくつかのパラメータを更新し、それを| teeにパイプすると、これがランダムに壊れてファイルが無効(サイズ0)。要約するとteeを使ってファイルをランダムに更新すると、linux bashスクリプト

、このコードは、パラメータを更新するために使用されます。

# based on the provided linenumber, add some comments, add the new value, delete old line 

sed -e "$lineNr a # comments" -e "$lineNr a $newValue" -e "$lineNr d" $myFile | sudo tee $myFile 

私はこのupdateコマンドを100回呼び出すスクリプトを設定します。 OSXでの共有ディレクトリ上のUbuntuのVM(Parallels Desktopの)で

  • この 動作は、この動作は40までに発生 UbuntuのパーティションにUbuntuのVM(Parallels Desktopの)で50回
  • までに発生なぜこれが起こっている(UbuntuのとIntelNUC)ネイティブシステム・オン回
  • この動作は15回

まで発生は、誰かが説明できますか?

ここでは、実験を実行できる完全に機能的なスクリプトもあります。

#!/bin/bash 
# main function at bottom 

#==================== 
#===HELPER METHOD==== 
#==================== 

# This method updates parameters with a new value. The replacement is performed linewise. 
doUpdateParameterInFile() 
{ 
    local valueOfInterest="$1" 
    local newValue="$2" 
    local filePath="$3" 

    # stores all matching linenumbers 
    local listOfLines="" 
    # stores the linenumber which is going to be replaced 
    local lineToReplace="" 

    # find value of interest in all non-commented lines and store related lineNumber 
    lineToReplace=$(grep -nr "^[^#]*$valueOfInterest" $filePath | sed -n 's/^\([0-9]*\)[:].*/\1/p') 

    # Update parameters 
    # replace the matching line with the desired value 
    oldValue=$(sed -n "$lineToReplace p" $filePath) 
    sed -e "$lineToReplace a # $(date '+%Y-%m-%d %H:%M:%S'): replaced: $oldValue with: $newValue" -e "$lineToReplace a $newValue" -e "$lineToReplace d" $filePath | sudo tee $filePath >/dev/null 

    # Sanity check to make sure file did not get corrupted by updating parameters 
    if [[ ! -s $filePath ]] ; then 
    echo "[ERROR]: While updating file it turned invalid." 
    return 31 
    fi 

} 

#=============================== 
#=== Actual Update Function ==== 
#=============================== 

main_script() 
{ 
    echo -n "Update Parameter1 ..." 
    doUpdateParameterInFile "Parameter1" "Parameter1 YES" "config.txt" 
    if [[ "$?" == "0" ]] ; then echo "[ OK ]" ; else echo "[FAIL]"; return 33 ; fi 

    echo -n "Update Parameter2 ..." 
    doUpdateParameterInFile "Parameter2" "Parameter2=90" "config.txt" 
    if [[ "$?" == "0" ]] ; then echo "[ OK ]" ; else echo "[FAIL]"; return 34 ; fi 

    echo -n "Update Parameter3 ..." 
    doUpdateParameterInFile "Parameter3" "Parameter3 YES" "config.txt" 
    if [[ "$?" == "0" ]] ; then echo "[ OK ]" ; else echo "[FAIL]"; return 35 ; fi 
} 

#================= 
#=== Main Loop === 
#================= 

#generate file config.txt 
printf "# Configfile with 3 Parameters\n#[Parameter1]\n#only takes YES or NO\nParameter1 NO \n\n#[Parameter2]\n#Parameter2 takes numbers\nParameter2 = 100 \n\n#[Parameter3]\n#Parameter3 takes YES or NO \nParameter3 YES\n" > config.txt 
cp config.txt config.txt.bkup 

# Start the experiment and let it run 100 times 
cnt=0 
failSum=0 
while [[ $cnt != "100" ]] ; do 
    echo "==========run: $cnt; fails: $failSum=======" 
    main_script 
    if [[ $? != "0" ]] ; then cp config.txt.bkup config.txt ; failSum=$(($failSum+1)) ; fi 
    cnt=$((cnt+1)) 
    sleep 0.5 
done 

よろしく DonPromillo

+2

のようなあなたのteeアプローチを使うのか?また、 'sed'を使ってファイルを処理するのとまったく同じ時にファイルを上書きするために' tee'を使用しているので、競合状態が最も発生しているようです。 'tee'が' sed'を得る前にファイルを切り詰めると '0'長さのファイルが得られます。あなたの 'sed'がそれをサポートしていれば、その場所でファイルを修正することができます。そうでなければ、出力を一時ファイルに書き込んで元の名前に移動してください。 –

+1

パイプの両側は非同期です。 'tee'が上書きする前に' sed'が 'myFile'の内容を完全に消費していることを保証することはできません。 – chepner

+0

@EricRenoufと@chepnerありがとうございました。私が「ティー」を使っていた理由は、基本的にはパイピングの好奇心です。 – DonPromillo

答えて

3

問題は、あなたが上書きするteeを使用しているということです(あなたは、単に/ bashscriptfileに貼り付けて、それを実行してコピーすることができるようにすべての必要なファイルは、スクリプトによって生成されます) と同時に、sedがそこから読み取ろうとしています。 teeを最初に切り捨てた場合、sedは空のファイルを取得し、もう一方の端には0の長さのファイルがあります。

は、あなたがGNU sedを持っている場合は、(他のバージョンが-iをサポートしていますが、それには、引数を必要とする)sedの場所にファイルを変更する必要があり-iフラグを使用することができます。あなたのsedがそれをサポートしていない場合、あなたはそれが一時ファイルへの書き込みがあり、

tmpname=$(mktemp) 
sed -e "$lineToReplace a # $(date '+%Y-%m-%d %H:%M:%S'): replaced: $oldValue with: $newValue" -e "$lineToReplace a $newValue" -e "$lineToReplace d" "$filePath" > "$tmpname" 
sudo mv "$tmpname" "$filePath" 

のように元の名前に戻ってそれを移動したり、元の権限を保持したい場合、あなたは何ができる可能

sudo sh -c "cat '$tmpname' > '$filePath'" 
rm "$tmpname" 

か、 `stdout`を捨てている場合、なぜあなたはこのため` tee`を使用している

sudo tee "$filePath" >/dev/null <"$tmpname" 
rm "$tmpname" 
+0

'sed'の出力を(一時ファイルの代わりに)変数に書き込むことも可能です。 – DonPromillo

+0

@DonPromilloファイルに戻す方法を慎重に考えれば、 'printf '%s'" $ contents ">" $ filePath "'私は思うはずです –

関連する問題