2013-10-16 14 views
6

CSVファイルをスプレッドシートXMLファイルに変換するためのシェルスクリプトをkshで作成しました。既存のCSVファイル(スクリプト内の変数へのパス)を受け取り、新しい出力ファイル.xlsを作成します。スクリプトには位置パラメータはありません。 CSVのファイル名は、現在、スクリプトにハードコードされています。パイプ入力によるスクリプトへの入力

このスクリプトを修正して、入力されたCSVデータをパイプから取り込み、.xls出力データをコマンドラインのファイルにパイプするかリダイレクト(>)できるようにしたいと考えています。

これはどのように達成されましたか?

パイプから入力を受け取るためのシェルスクリプトを作成する方法に関するドキュメントを見つけるのには苦労しています。 '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

コマンドは、それらを起動するプロセスから自分の標準入力を継承します。 catはその標準入力を継承しているので、あなたのシェルスクリプトに

#!/bin/bash 
cat > foo.txt 

配管データは、そのデータを読み取るためにcatが発生します。あなたのケースでは、あなたのスクリプトは、それは簡単なサンプルスクリプト実行する各コマンドの標準入力を提供しますあなたのスクリプトから。

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

readコマンドを使用すると、読み取りまたはスクリプトの標準入力を処理するために、別のコマンドを持っていない場合、シェル変数に標準入力からテキストを読み取るためのシェルによって提供されます。

#!/bin/bash 

read foo 
echo "You entered '$foo'" 

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

(スクリプトを作成している)外部プログラムがすでにstdinから入力を受けている場合、スクリプトは何もする必要はありません。

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

その後

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

出力

1 
2 
3 
8

一つの問題はここにあります:たとえば、awkは行ごとに単語をカウントするために、標準入力からとても短いスクリプトを読み込みます。最初にstdinに入力があることを確認せずにスクリプトを実行すると、何かが入力されるまでハングします。

これを回避するには、最初にstdinがあることを確認し、そうでない場合は、コマンドライン引数を使用してください。

テストに続いて

#!/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 

「testPipe.sh」というスクリプトを作成します。

は、私たちのスクリプトに出力を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 

出力:

./testPipe.sh invalidFile.txt 

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

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

そして最後に、のは、無効なファイル名を使用してテストしてみましょうreadとcatのようなプログラムは、シェル内で使用できる場合はstdinを使用します。そうでなければ、入力を待つでしょう。

クレジットは、入力を標準入力のチェック方法を示す彼の答えに、このページからマイクに行く:https://unix.stackexchange.com/questions/33049/check-if-pipe-is-empty-and-run-a-command-on-the-data-if-it-isnt?newreg=fb5b291531dd4100837b12bc1836456f

関連する問題