2013-10-16 57 views
6

我已經在ksh中編寫了一個shell腳本來將CSV文件轉換爲Spreadsheet XML文件。它需要一個現有的CSV文件(腳本中的變量路徑),然後創建一個新的輸出文件.xls。該腳本沒有位置參數。 CSV的文件名稱目前被硬編碼到腳本中。將管道輸入到腳本中

我想修改腳本,以便它可以從管道輸入CSV數據,以便.xls輸出數據也可以通過管道或重定向(>)到命令行上的文件中。

這是如何實現的?

我正在努力尋找關於如何編寫shell腳本以從管道獲取輸入的文檔。看起來'read'只用於kb的std輸入。

謝謝。

編輯:下面的腳本爲信息(現修正通過貓採取輸入從管道,按照該問題的答案

#!/bin/ksh 
#Script to convert a .csv data to "Spreadsheet ML" XML format - the XML scheme for Excel 2003 
# 
# Take CSV data as standard input 
# Out XLS data as standard output 
# 

DATE=`date +%Y%m%d` 

#define tmp files 
INPUT=tmp.csv 
IN_FILE=in_file.csv 

#take standard input and save as $INPUT (tmp.csv) 
cat > $INPUT 

#clean input data and save as $IN_FILE (in_file.csv) 
grep '.' $INPUT | sed 's/ *,/,/g' | sed 's/, */,/g' > $IN_FILE 

#delete original $INPUT file (tmp.csv) 
rm $INPUT 

#detect the number of columns and rows in the input file 
ROWS=`wc -l < $IN_FILE | sed 's/ //g' ` 
COLS=`awk -F',' '{print NF; exit}' $IN_FILE` 
#echo "Total columns is $COLS" 
#echo "Total rows is $ROWS" 

#create start of Excel File 
echo "<?xml version=\"1.0\"?> 
<?mso-application progid=\"Excel.Sheet\"?> 
<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\" 
     xmlns:o=\"urn:schemas-microsoft-com:office:office\" 
     xmlns:x=\"urn:schemas-microsoft-com:office:excel\" 
     xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\" 
     xmlns:html=\"http://www.w3.org/TR/REC-html40\"> 
<DocumentProperties xmlns=\"urn:schemas-microsoft-com:office:office\"> 
     <Author>Ben Hamilton</Author> 
     <LastAuthor>Ben Hamilton</LastAuthor> 
     <Created>${DATE}</Created> 
     <Company>MCC</Company> 
     <Version>10.2625</Version> 
</DocumentProperties> 
<ExcelWorkbook xmlns=\"urn:schemas-microsoft-com:office:excel\"> 
     <WindowHeight>6135</WindowHeight> 
     <WindowWidth>8445</WindowWidth> 
     <WindowTopX>240</WindowTopX> 
     <WindowTopY>120</WindowTopY> 
     <ProtectStructure>False</ProtectStructure> 
     <ProtectWindows>False</ProtectWindows> 
</ExcelWorkbook> 

<Styles> 
     <Style ss:ID=\"Default\" ss:Name=\"Normal\"> 
      <Alignment ss:Vertical=\"Bottom\" /> 
      <Borders /> 
      <Font /> 
      <Interior /> 
      <NumberFormat /> 
      <Protection /> 
     </Style> 
     <Style ss:ID=\"AcadDate\"> 
     <NumberFormat ss:Format=\"Short Date\"/>  
     </Style> 
</Styles> 
<Worksheet ss:Name=\"Sheet 1\"> 
<Table> 
<Column ss:AutoFitWidth=\"1\" />" 

#for each row in turn, create the XML elements for row/column 
r=1 
while ((r <= $ROWS)) 
do 
    echo "<Row>\n" 
    c=1 
    while ((c <= $COLS)) 
    do 
     DATA=`sed -n "${r}p" $IN_FILE | cut -d "," -f $c ` 

     if [[ "${DATA}" == [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9][0-9][0-9] ]]; then 

      DD=`echo $DATA | cut -d "." -f 1` 
      MM=`echo $DATA | cut -d "." -f 2` 
      YYYY=`echo $DATA | cut -d "." -f 3`  
      echo "<Cell ss:StyleID=\"AcadDate\"><Data ss:Type=\"DateTime\">${YYYY}-${MM}-${DD}T00:00:00.000</Data></Cell>" 
     else   
      echo "<Cell><Data ss:Type=\"String\">${DATA}</Data></Cell>" 
     fi 
     ((c+=1)) 
    done 
    echo "</Row>" 
    ((r+=1)) 
done 

echo "</Table>\n</Worksheet>\n</Workbook>" 


rm $IN_FILE > /dev/null 

exit 0 
+0

顯示我們的腳本... – devnull

回答

20

命令,從啓動它們的進程繼承其標準輸入。在你的情況,腳本提供,它運行一個簡單的例子腳本每個命令它的標準輸入:

#!/bin/bash 
cat > foo.txt 

管道數據到外殼腳本使得cat讀取該數據,因爲cat繼承了其標準輸入從你的腳本。

$ echo "Hello world" | myscript.sh 
$ cat foo.txt 
Hello world 

read命令由shell讀取從標準輸入文本到一個shell變量,如果你沒有其他命令來讀取或處理腳本的標準輸入你提供。

#!/bin/bash 

read foo 
echo "You entered '$foo'" 

$ echo bob | myscript.sh 
You entered 'bob' 
4

如果外部程序(您腳本)已經採取從標準輸入,你的腳本不需要做任何事情。例如,AWK從stdin讀取,所以很短的腳本來計算單詞每行:

#!/bin/sh 
awk '{print NF}' 

然後

./myscript.sh <<END 
one 
one two 
one two three 
END 

輸出

1 
2 
3 
8

這裏有一個問題。如果你沒有首先檢查腳本來運行腳本以確保在stdin上有輸入,那麼它將掛起直到輸入內容。

所以,爲了解決這個問題,你可以檢查以確保首先有stdin,如果沒有,那麼使用命令行參數而不是命令行參數。

創建一個名爲「testPipe.sh」腳本

#!/bin/bash 
# Check to see if a pipe exists on stdin. 
if [ -p /dev/stdin ]; then 
     echo "Data was piped to this script!" 
     # If we want to read the input line by line 
     while IFS= read line; do 
       echo "Line: ${line}" 
     done 
     # Or if we want to simply grab all the data, we can simply use cat instead 
     # cat 
else 
     echo "No input was found on stdin, skipping!" 
     # Checking to ensure a filename was specified and that it exists 
     if [ -f "$1" ]; then 
       echo "Filename specified: ${1}" 
       echo "Doing things now.." 
     else 
       echo "No input given!" 
     fi 
fi 

然後進行測試:

讓我們一些東西輸出添加到test.txt文件,然後通過管道到我們的腳本。

printf "stuff\nmore stuff\n" > test.txt 
cat test.txt | ./testPipe.sh 

輸出: Data was piped to this script! Line: stuff Line: more stuff

現在讓我們來測試,如果不提供任何輸入:

./testPipe.sh 

輸出: No input was found on stdin, skipping! No input given!

現在讓我們來測試,如果提供有效的文件名:

./testPipe.sh test.txt 

輸出: No input was found on stdin, skipping! Filename specified: test.txt Doing things now..

最後,讓我們來測試使用無效的文件名:

./testPipe.sh invalidFile.txt 

輸出: No input was found on stdin, skipping! No input given!

說明: 像read和cat這樣的程序將使用stdin(如果它在shell中可用),否則它們將等待輸入。

幸得邁克從這個頁面在他的回答顯示瞭如何檢查標準輸入輸入:https://unix.stackexchange.com/questions/33049/check-if-pipe-is-empty-and-run-a-command-on-the-data-if-it-isnt?newreg=fb5b291531dd4100837b12bc1836456f