1. 程式人生 > 其它 >解決dos2unix/unix2dos報錯,並在家目錄下生成u2dtmp*檔案問題

解決dos2unix/unix2dos報錯,並在家目錄下生成u2dtmp*檔案問題

最近接到一個 case:大資料分析那邊反饋我們這邊推送的資料同比去年同期少了很多。這是很不正常的,因為業務一直在增長。

於是,我開始順藤摸瓜的跟進。一開始就發現一個小問題:scp 推送檔案指令碼執行後居然會報錯:

[root@netdata :/data]# sh pushdata.sh dos2unix: converting file pushdata.log to UNIX format ... dos2unix: problems renaming './u2dtmp8jwsge' to 'pushdata.log' output file remains in './u2dtmp8jwsge' dos2unix: problems converting file pushdata.log

原來是將生成的日誌轉換成 Unix 格式。按理說應該不會影響資料的推送,不過還是順手處理下。

奇怪的是,人工去執行 dos2unix 卻是正常的,看來和指令碼有關係了。看了半天的指令碼,也沒看出哪兒有明顯的錯誤:

dos2unix  /data/pushdata.log

還是先不浪費時間自己摸索了,直接丟百度一下,發現並沒有什麼 luan 用。進而丟谷歌,終於在一個國外論壇找到了正確的解釋:

It turns out that when you run the script from cron your current directory (PWD) is set to your home directory. Unix2dos creates the temporary file used in the conversion in your home directory then can't find it to rename it. Not sure why it can't find it. I added a change directory command (cd) and Unix2dos worked.

大概意思是,crontab 計劃任務中的腳本當前執行路徑預設會設定為家目錄。所以,dos2unix/unix2dos 會在家目錄下建立轉換後的臨時檔案(u2dtmp****),導致命令無法在目標路徑找到將臨時檔案,並重命名為被處理的檔名,作者表示他也不知道為什麼會找不到。不過他給出的解決辦法就是:在腳本里面加入 cd 到日誌所在路徑的命令即可。

比如,本文 case 中可以在指令碼一開始處加入 cd /data

我解決之後發現就釋然了。其實問題的原因很簡單:

crontab 下執行的指令碼,預設的工作路路徑是家目錄(手動執行的指令碼,預設的工作路徑則是當前所在目錄)。由於指令碼中並沒有加入工作路徑的定義,所以就用了預設的家目錄作為工作路徑。

dos2unix/unix2dos 這 2 個命令的工作原理是:在工作路徑將轉換後的內容儲存為一個臨時檔案,然後在將這個臨時檔案重新命名為被處理的檔案,完成格式轉換。若工作路徑和被處理檔案並不在同一個目錄,就會導致這個報錯,生成的臨時檔案也被保留下來。

所以,若是 crontab 中存在這個問題,將會在家目錄下生成大量的 u2dtmp*** 臨時檔案。

哦了,若是發現 dos2unix/unix2dos 報類似錯誤,肯定是指令碼沒有定義工作路徑。可以在指令碼的前面加入 cd 到檔案所在目錄再執行 dos2unix/unix2dos 即可。

當然,如果只是要轉換格式,我們還有多種替代方案,沒必要吊死在 dos2unix/unix2dos 上。畢竟有些系統可能沒有這 2 個命令。

替代命令①:sed

#以下2種都可以: 
sed -e 's/.$//g' oldfile > newfile 
sed 's/^M//' oldfile > newfile #注意 ^M = Ctrl + v,Ctrl + m 命令組合打印出來的字元

替代命令②:tr

cat oldfile | tr -d "r" > newfile

好了,解決了這個問題,我該繼續跟進同步問題了。