2011-10-09 29 views
0

我在外殼寫這個小程序:殼牌程序代碼約:正則表達式和文件處理

#!/bin/bash 

#*************************************************************** 
# Synopsis: 
# Read from an inputfile each line, which has the following format: 
# 
# llnnn nnnnnnnnnnnnllll STRING lnnnlll n nnnn nnnnnnnnn nnnnnnnnnnnnnnnnnnnn ll ll 
# 
# where: 
# n is a <positive int> 
# l is a <char> (no special chars) 
# the last set of ll ll could be: 
# - NV 
# - PV 
# 
# Ex: 
# AVO01 000060229651AVON FOOD OF ARKHAM C A S060GER 0 1110 000000022 00031433680006534689 NV PV 
# 
# The program should check, for each line of the file, the following: 
# I) If the nnn of character llnnn (beggining the line) is numeric, 
# this is, <int> 
# II) If the character ll ll is NV (just one set of ll) then 
# copy that line in an outputfile, and add one to a counter. 
# III) If the character ll ll is NP (just one set of ll) then 
#  copy that line in an outputfile, and add one to a counter. 
# 
# NOTICE: could be just one ll. Ex: [...] NV [...] 
#         [...] PV [...] 
#   or both Ex: [...] NV PV [...] 
# 
# 
# Execution (after generating the executable): 
# ./ inputfile outputfileNOM outputfilePGP 
#*************************************************************** 


# Check the number of arguments that could be passed. 
if [[ ${#@} != 3 ]]; then 
     echo "Error...must be: myShellprogram <inputfile> <outputfileNOM> <outputfilePGP>\n" 
    exit 
fi 

#Inputfile: is in position 1 on the ARGS 
inputfile=$1 
#OutputfileNOM: is in position 2 on the ARGS 
outputfileNOM=$2 
#OutputfilePGP: is in position 3 on the ARGS 
outputfilePGP=$3 

#Main variables. Change if needed. 
# Flags the could appear in the <inputfile> 
# 
# ATTENTION!!!: notice that there is a white space 
# before the characters, this is important when using 
# the regular expression in the conditional: 
# if [[ $line =~ $NOM ]]; then [...] 
# 
# If the white space is NOT there it would match things like: 
# ABCNV ... which is wrong!! 
NOM=" NV" 
PGP=" PV" 
#Counters of ocurrences 
countNOM=0; 
countPGP=0; 


#Check if the files exists and have the write/read permissions 
if [[ -r $inputfile && -w $outputfileNOM && -w $outputfilePGP ]]; then 
    #Read all the lines of the file. 
    while read -r line 
     do 
      code=${line:3:2} #Store the code (the nnn) of the "llnnn" char set of the inputfile 

      #Check if the code is numeric 
      if [[ $code =~ ^[0-9]+$ ]] ; then 

       #Check if the actual line has the NOM flag 
       if [[ $line =~ $NOM ]]; then 
        echo "$line" >> "$outputfileNOM" 
        ((++countNOM)) 
       fi 

       #Check if the actual line has the PGP flag 
       if [[ $line =~ $PGP ]]; then 
        echo "$line" >> "$outputfilePGP" 
        ((++countPGP)) 
       fi 

      else 
       echo "$code is not numeric" 
       exit 

      fi  

     done < "$inputfile" 

    echo "COUN NON $countNOM"  
    echo "COUN PGP $countPGP" 
else 
    echo "FILE: $inputfile does not exist or does not have read permissions" 
    echo "FILE: $outputfileNOM does not exist or does not have write permissions" 
    echo "FILE: $outputfilePGP does not exist or does not have write permissions" 
fi 

我有一些問題:

我)當我這樣做:

if [[ -r $inputfile && -w $outputfileNOM && -w $outputfilePGP ]]; then 
[...] 
else 
    echo "FILE: $inputfile does not exist or does not have read permissions" 
    echo "FILE: $outputfileNOM does not exist or does not have write permissions" 
    echo "FILE: $outputfilePGP does not exist or does not have write permissions" 
fi 

我想打印其他的東西,因此,這是,打印正確的消息。例如:如果「$ outputfileNOM」沒有寫入權限,只需打印該錯誤。但是,我不希望把大量的if/else語句,例如:

if [[ -r $inputfile ]]; then 
[...] 
if [[-w $outputfileNOM ]] then 
[...] 
else 
    For the READ permission, and the other else for the WRITE 

有沒有辦法做到這一點,利用嵌套的方式沒有,並維持可讀性。

II)關於:

if [[ -r $inputfile && -w $outputfileNOM && -w $outputfilePGP ]] 

是確定的,如果我使用的標誌,而不是 「-x」 -r或-w。我沒有一個清晰的定義是什麼意思:

-x FILE 
      FILE exists and execute (or search) permission is granted 

三)注意我的代碼中的注意標籤。我注意到有一些可能性,例如:在之前,之後或之前或之後有空格。我相信輸入文件的一致性,但如果它們改變了,它會爆炸。我能在這種情況下做什麼?有沒有一種優雅的方式來管理它? (例外?)

非常感謝!

+0

這有什麼特別的理由寫在sh?你會得到一個更清潔的Perl或Python程序。 –

+0

@Rafe:是的,我沒有選擇,是要寫在shell中的要求。 – Kani

+0

順便說一句 - 如果你準備了一個精簡版的代碼 - 你可能會得到更多的關注 - 就足以展現不良行爲。我甚至沒有看過這個,只是它絆倒了一個非常令人沮喪的記憶。 – dmckee

回答

0

嗯,謝謝幫助我的人。在他們的建議,我會回答我自己的問題:

關於:

I)雖然這種解決方案使用條件,很優雅:

#File error string 
estr='ERROR: %s files does no exist or does not have %s permissions.\n' 

#Check if the files exists and have the write/read permissions 
[ -r $inputfile ] || { printf "$estr" "<$inputfile>" "read" && exit; } 
[ -w $outputfileNOM ] || { printf "$estr" "<$outputfileNOM>" "write" && exit; } 
[ -w $outputfilePGP ] || { printf "$estr" "<$outputfilePGP>" "write" && exit; } 

注意;退出後

II)從CHMOD的手冊:

字母rwxXst選擇文件模式位爲受影響的用戶:讀(r),寫(w),執行(或搜索目錄)( X)...

而且從維基百科(文件系統權限):

讀permi ssion,它授予讀取文件的能力。當爲目錄設置時,此權限授予讀取目錄中文件名稱的能力(但不能查找任何有關它們的更多信息,例如內容,文件類型,大小,所有權,權限等)。

寫入權限,它授予修改文件的能力。當爲目錄設置時,此權限授予修改目錄中條目的能力。這包括創建文件,刪除文件和重命名文件。

執行權限,授予執行文件的能力。必須爲可執行二進制文件(例如,編譯的C++程序)或shell腳本(例如Perl程序)設置此權限,以便操作系統運行它們。爲目錄設置時,此權限授予遍歷樹的權限以訪問文件或子目錄,但不會查看目錄內文件的內容(除非設置了讀取)。

三)感謝@dmckee的鏈接和海龜

# ATTENTION!!!: notice the \< and \> surrounding 
# the characters, this is important when using 
# the regular expression in the conditional: 
# if [[ $line =~ $NOM ]]; then [...] 
# 
# If those characters are NOT there it would match things like: 
# ABCNV ... which is wrong!! 
# They (the \< and \>) indicate that the 'NV' can't be 
# contained in another word. 
NOM='\<NV\>' 
PGP='\<PV\>' 
0

我以前被=~運營商咬過。

原則上我會告訴你報價參數(即... =~ "$NOM"),starting with bash 3.2 there is a special behavior=~ ""。鏈路(),它是相當羅嗦說:

ö引用字符串參數到[[命令的=〜(正則表達式)操作者現在 力字符串匹配,與其它模式匹配運算符。

E14)爲什麼引述圖案參數傳遞給正則表達式匹配 條件運算符(=〜)原因正則表達式匹配停止工作?

在bash-3.2之前的bash版本中,沒有指定對[[command's =〜運算符]引用常規 表達式參數的效果。 的實際效果是,雙引述圖案參數所需 反斜線引用特殊模式字符,這與由雙引號字膨脹進行 反斜槓處理干擾和是 與==殼圖案匹配操作者如何處理 不一致引用的字符。

在bash-3中。2,shell被改爲內部引用單個字符 和雙引號字符串參數給=〜運算符,這就抑制了 字符特殊含義的正則表達式處理 ('\', [',\',(', ), *「 +',?」,{', |」,^', and $‘)和力 他們按字面匹配這是它的模式參數的'==’模式 匹配運營商如何對待引述部分一致

由於引用字符串參數的處理方式發生了變化,因此出現了幾個問題 ,其中主要是pr模式參數 中的空白區域以及bash-3.1和bash-3.2之間引用字符串的不同處理。 這兩個問題都可以通過使用shell變量來保存模式來解決。 由於在[[command]的所有 操作數中擴展shell變量時不執行字分割,因此用戶可以在分配變量時根據需要引用 ,然後將值展開爲單個字符串,其中 可能包含空格。第一個問題可以通過使用反斜槓 或任何其他引用機制來解決模式中的空白問題。

你可能會考慮一些沿着NOM="[ ]NV"的行。 (請注意,我沒有測試過這個。)

+0

謝謝你的提示!等待我能得到[I],[II]和[III]的答案! – Kani