2016-08-17 149 views
2

我是bash腳本編程新手,我遇到了一個腳本問題,我想編寫一個25歲以下的驅動程序列表從一個充滿XML文件的文件夾中讀取他們的生日,並計算他們的年齡,一旦我確定他們在25歲以下,驅動程序數據的文件名就會保存到一個文本文件中,腳本一直工作到某一點,然後它,停止我得到的錯誤是:BASH錯誤:語法錯誤:期望的操作數(錯誤標記爲「)

gdate: extra operand ‘+%s’ 
Try 'gdate --help' for more information. 
DriversUnder25.sh: line 24: (1471392000 - )/60/60/24 : syntax error: operand expected (error token is ")/60/60/24 ") 

這裏是我的代碼:

#!/bin/bash 

# define directory to search and current date 
DIRECTORY="/*.xml" 
CURRENT_DATE=$(date '+%Y%m%d') 

# loop over files in a directory 
for FILE in $DIRECTORY; 
do 
    # grab user's birth date from XML file 
    BIRTH_DATE=$(sed -n '/Birthdate/{s/.*<Birthdate>//;s/<\/Birthdate.*//;p;}' $FILE) 

    # calculate the difference between the current date 
    # and the user's birth date (seconds) 
    DIFFERENCE=$((($(gdate -ud $CURRENT_DATE +'%s') - $(gdate -ud $BIRTH_DATE +'%s'))/60/60/24)) 

    # calculate the number of years between 
    # the current date and the user's birth date 
    YEARS=$(($DIFFERENCE/365)) 

    # if the user is under 25 
    if [ "$YEARS" -le 25 ]; then 
    # save file name only 
    FILENAME=`basename $FILE` 
    # output filename to text file 
    echo $FILENAME >> DriversUnder25.txt 
    fi 
done 

我不知道爲什麼它正確輸出前10個文件名,然後停止。任何想法,爲什麼這可能會發生?

+0

檢查'$ BIRTH_DATE'的值。你可以將它回顯到stderr,用'echo birthdate查看它是\「$ {BIRTH_DATE} \」「1>&2' –

+0

我得到的結果是'birthdate is」19920215「' – Kim

+0

使用'set -x'來查看如何擴展變量值你應該在你的第10條記錄上看到數據正在發生變化你的XML文件可能有問題,日期格式不同或其他問題嗎?祝你好運 – shellter

回答

0

問題是在一些文件中有多個驅動程序,因此將多個出生日期導入到同一個字符串中。我的解決方案如下:

#!/bin/bash 

# define directory to search and current date 
DIRECTORY="/*.xml" 
CURRENT_DATE=$(date '+%Y%m%d') 

# loop over files in a directory 
for FILE in $DIRECTORY; 
do 
    # set flag for output to false initially 
    FLAG=false 

    # grab user's birth date from XML file 
    BIRTH_DATE=$(sed -n '/Birthdate/{s/.*<Birthdate>//;s/<\/Birthdate.*//;p;}' $FILE) 

    # loop through birth dates in file (there can be multiple drivers) 
    for BIRTHDAY in $BIRTH_DATE; 
    do 
    # calculate the difference between the current date 
    # and the user's birth date (seconds) 
    DIFFERENCE=$((($(gdate -ud $CURRENT_DATE +'%s') - $(gdate -ud $BIRTHDAY +'%s'))/60/60/24)) 

    # calculate the number of years between 
    # the current date and the user's birth date 
    YEARS=$(($DIFFERENCE/365)) 

    # if the user is under 25 
    if [ "$YEARS" -le 25 ]; then 
     # save file name only 
     FILENAME=`basename $FILE` 
     # set flag to true (driver is under 25 years of age) 
     FLAG=true 
    fi 
    done 

    # if there is a driver under 25 in the file 
    if $FLAG == true; then 
    # output filename to text file 
    echo $FILENAME >> DriversUnder25.txt 
    fi 
done 
+2

運行您的代碼也許您的意思是'if [「$ FLAG」= true] '?如果'FLAG'保證爲'true'或'false',這將會按照寫入的方式工作,但它有一些偶然的原因(因爲這些命令都忽略了它的參數並返回一個反映它名字的退出狀態) 。因此,如果$ FLAG == false或者如果$ FLAG foobar的行爲與if $ FLAG == true的行爲完全相同。 –

+0

(...在自我接受超時過期後,順便說一下,您可以通過點擊該答案的複選框來標記問題)。 –

3

您需要引用$BIRTH_DATE的擴展來防止對值中的空格進行分詞。 (這是引用所有的參數擴展很好的做法,除非你有一個很好的理由不來,因爲這個原因。)

DIFFERENCE=$((($(gdate -ud "$CURRENT_DATE" +'%s') - $(gdate -ud "$BIRTH_DATE" +'%s'))/60/60/24)) 

(您的評論基礎,這將可能至少允許gdate到給你一個更好的錯誤消息)

1

的最佳實踐的實施將是這個樣子:

directory=/ # patch as appropriate 
current_date_unix=$(date +%s) 

for file in "$directory"/*.xml; do 
    while IFS= read -r birth_date; do 
     birth_date_unix=$(gdate -ud "$birth_date" +'%s') 
     difference=$(((current_date_unix - birth_date_unix)/60/60/24)) 
     years=$((difference/365)) 
     if ((years < 25)); then 
      echo "${file%.*}" 
     fi 
    done < <(xmlstarlet sel -t -m '//Birthdate' -v . -n <"$file") 
done >DriversUnder25.txt 

如果此腳本需要可用,但我的人員沒有安裝xmlstarlet,則可以生成XSLT模板,然後使用xsltproc(可在現代操作系統上使用)。

也就是說,如果運行此一次,並捆綁其輸出與你的腳本:

xmlstarlet sel -C -t -m '//Birthdate' -v . -n >get-birthdays.xslt 

...那麼該腳本可以被修改,以取代xmlstarlet

xsltproc get-birthdays.xslt - <"$file" 

注:

  • 的X ML輸入文件正在用an actual XML parser讀取。
  • 當擴展for file in "$directory"/*.xml時,引用擴展,但glob不是(因此允許腳本在其名稱中使用空格,glob字符等操作)。
  • 對於循環,輸出文件正在打開一次,而不是每行輸出一次(減少不必要地打開和關閉文件的開銷)。
  • 使用小寫變量名稱以符合POSIX conventions(指定對操作系統和shell具有含義的變量具有全部大寫名稱,並且至少包含一個小寫字符的名稱集合是保留給應用程序使用;而所討論的文檔是關於環境變量的,而shell變量共享一個名稱空間,從而使公約相關)。
相關問題