2016-07-26 34 views
0

我想寫一個shell腳本,它可以確定輸入文件中的行是以DOS(CR/LF)還是Unix(LF)換行符結尾。如何從DOS腳本中區分DOS換行文件

我該如何做出這個決定?

+0

您可以在您的if []中使用回聲「ASCII」,並在您的其他文件 –

+2

中使用echo「CR/LF」提供此信息和更多信息。是否有一個令人信服的理由來重塑它? – John1024

+0

順便說一句 - 我的編輯在這裏是嚴厲的,但也有必要有一個允許的網站規則的問題。我們非常不滿意「請爲我編寫我的程序」問題 - 一個問題應該專門針對您在嘗試實現您的目標時遇到的技術問題。 –

回答

1

一種方法是避免依賴外部工具,如file如下:

#!/bin/bash 
#  ^^^^- important! not /bin/sh, and do not run with "sh scriptname" 

# if given a command-line argument, redirect from it as stdin 
if [ -n "$1" ]; then 
    exec <"$1" || exit 
fi 

# Read a single line from stdin into a variable 
if ! IFS= read -r line; then 
    # we were unable to read a line 
    echo "Invalid or Empty" 
    exit 1 
fi 

# Check whether the last character of that line is a CR 
case $line in 
    *$'\r') echo "DOS" ;; 
    *)  echo "UNIX" ;; 
esac 

這工作,因爲在bash(雖然不是POSIX SH),$'\r'是語法回車(CR)字符。由於read會讀取第一個看到的LF,因此在DOS文件中,從該文件讀取的行中的最後一個字符將是CR。

+0

好的解決方案,但不完全是OP要求的。如果我正確理解這個問題,那麼在檢查時,文件*是否以LF或CRLF結束*是否在第一個* LF之前是CR。當輸入文件是一個二進制文件或帶有混合行結尾的文件(某些LF和某些CRLF)或最後一行沒有行結束標記的文件時,這會有所不同。 – user1934428

+1

@ user1934428太懶得檢查OP的原始問題,但我也將它解釋爲「每行以......結尾......」,正如主題標題所建議的那樣。 – tripleee

+1

@ user1934428克服了我的懶惰,並修正了編輯問題中的歧義。實際上,OP最初詢問是否識別文件的結尾。 – tripleee

0

,您可以先

last2=`tail -c 2 your_file | od -x -A n` 

這種存儲在變量last2最後兩個字節your_file的十六進制表示。唯一的問題是字節順序。在一個big-endian機器上,它將是0a0d,在一個小端機器0d0a上。

現在你既可以根據您的硬件的存儲方式編寫測試,或者你可以欺騙和寫入

if [ $last2 = 0a0d -o $last2 = 0d0a ] 
then 
    # Cheating! If the file ends in LFCR, it would incorrectly 
    # say that it is CRLF 
    echo File ends in CRLF 
fi 
+0

對於沒有最後一行結束標記的DOS文件,這將無法可靠地工作。 – tripleee

+0

的確如此,但是,誠實地說:如果目標是真正地猜測它是否是DOS文件,我認爲最安全的方法就是依靠@文件工具,正如@ John1024所建議的那樣。即使在你的方法中,如果文件是一個二進制文件,它的流中恰好有0x0d和/或0x0a,我們也會遇到問題。但無論如何,瞭解爲什麼需要這種分類將會有所幫助。 – user1934428

1

如果檢查的第一行就足夠了,像

perl -ne 'exit ($_ =~ /\r$/)' file 

你可以在Bash中做同樣的事情;

lffile() { 
    local REPLY 
    read -r <"$1" 
    case $REPLY in *$'\r') return 1;; *) return 0;; esac 
} 

這需要$'\r' Bash> = 3.x的C風格字符串。如果你可以在腳本中可靠地,可移植地嵌入文字回車符,那麼你甚至可以使用sh來做這個小改動。下面以一個討厭的全球持有回車符:

lffile_cr=$(printf '\r') 
lffile() { 
    # local is not POSIX; simply overwrite REPLY 
    read -r <"$1" 
    case $REPLY in *"$lffile_cr") return 1;; *) return 0;; esac 
} 

在最一般的情況下,一個文件可能有混線的結局,但如果我們假設行結尾是一致的(和/或得到一個對於那個不起眼的角落案例,50%的命中或錯過率是可以接受的),讀第一行就足夠了。