2016-06-20 86 views
1

網上搜索我能弄清楚如何逐行讀取一個文件行後:讀寫逐行在bash腳本

while read p; do 
    echo $p 
done < file.txt 

但我真的想修改行的文件中。 例如:

while read p; do 
    if condition 
    then 
    echo $p | perl -i -pe 's/a/b/' 
    fi 
done < file.txt 

但是,這實際上並沒有修改文件。

+3

所有的文本處理工具都可以逐行讀取文件並進行處理,因此不需要涉及bash循環。 – karakfa

+1

同意@karakfa:你知道'sed -i'/ a/b /'文件'可以一次處理整個文件,效率更高,並且(顯然)代碼少得多嗎?祝你好運。 – shellter

+0

如果你想編輯文件,爲什麼不使用編輯器? 「ex」和「ed」浮現在腦海中... –

回答

1

更新  一個更好版本的bash的代碼添加。感謝Charles Duffy的評論。


你的Perl一行程序需要線管道輸送到它通過echo $p |,得到它的標準輸入的方式。它並沒有對文件本身任何目標,因此-i標誌無效。 -p使它打印到標準輸出流。因此,整行echo ...不會觸及該文件。

您可以將輸出重定向到一個新的文件,然後移動覆蓋file.txt。這是一個簡單的例子,它將每行添加到一個新文件中。要獲得更好的bash代碼,請參閱下面的更新。

while read p; do 
    if condition 
    then 
     echo $p | perl -pe 's/a/b/' >> temp_out.txt 
    else 
     echo $p >> temp_out.txt 
    fi 
done < file.txt 
mv temp_out.txt file.txt 

我們必須添加else其中所有未修改的行也被附加。請注意,通常我們不能只替換一些行,但整個文件必須重寫。

如果這是所有腳本就可以用一個非常簡單的一行做到這一點,一眼望不到頭。如果有更多的工作完成後,你還可以把它所有的Perl腳本,但我認爲有可能是一個bash腳本,其他充分的理由。


更新  一個更好的版本以上。見readechoBuiltins in Bash manual

  • 追加每一行打開文件重新而不需要每個時間。 只是在循環結束時重定向,很像它在終端中完成

  • read使用反斜線進行轉義,將其從輸入中刪除。先將其關閉與被除去-r

  • 尾隨空格,作爲破線成單詞的一部分。通過取消設置控制哪些字符用於分割的變量來抑制此問題,IFS=

  • echo $p可以做各種意想不到的事情。格式化的打印效果較好,printf '%s\n' "$p",或至少echo "$p"

有了這個,

while IFS= read -r p; do 
    if condition 
    then 
     echo "$p" | perl -pe 's/a/b/' 
    else 
     echo "$p" 
    fi 
done <file.txt> temp_out.txt 
mv temp_out.txt file.txt 

最後,如果Perl的一個班輪的唯一目的是運行一個簡單的替換,它是在殼體中簡單地做這件事要比爲每條生產線建立一條管道並運行一個全新的過程要好得多。

echo "${p//a/b}" 

感謝Charles Duffy在評論中提出了所有這些要點。


關於Perl單線程的幾點意見。請參閱文檔perlrun

命令perl -e '...'執行''之間的任何有效的Perl代碼。當我們添加-n-p開關時,它也會讀取標準輸入並在該行上執行該代碼,其中-p也會在處理完每行後打印出來。標準輸入可以從文件被提供給它,

perl -pe '...' input.txt 

在這種情況下添加-i標誌將導致在該文件中就地被改變。或者,該輸入可以被管道輸送到它,例如

echo "input text" | perl -pe '...' 

在這種情況下,經處理的線被印刷到標準輸出。這可以重定向到一個文件,如上面的答案。


要在時間線,你只需要在命令行中

perl -i -pe 's/a/b/' file.txt 

。如果有更多的工作要做,那麼它很可能是更好的把它改變給定文件在劇本當然。在這種情況下,單行程序也可以是bash腳本中的命令,替換上面的所有代碼(除非某些bash特定的功能是處理行的首選)。

+0

把'temp_out.txt'放在每個'echo'上是非常低效的 - 每次你想寫入輸出文件時都會重新打開輸出文件,而不是隻爲一個文件描述符打開寫入整個操作。 –

+1

將''temp_out.txt'放在循環中的'done'之後,並且避免所有這些「打開」和「關閉」操作。 –

+0

另外''echo $ p'是越野車。使用'printf'%s \ n'「$ p」',或者至少'echo「$ p」' - 儘管後者仍然會執行像刪除只包含'-n'這樣的行,它不會有'echo $ p'的不良副作用,它將用當前目錄中的文件列表替換包含'*'的行,用空格替換標籤等。 –