2016-10-23 239 views
1

我的目標是讀取一個.csv文件,反轉每一行,然後將結果寫出到另一個文件中,並且我成功地實現了這一目標。循環遍歷Bash中的所有列

我的代碼的問題是,我不得不指定我的csv文件(f1,f2,f3等)中的列數。如何在沒有指定不知道.csv文件內容的場景中的列數的情況下遍歷所有列?

PS:我在嘗試之前嘗試在論壇上尋找答案,但是我確實找不到任何有用的東西!

input="/path/to/file" 
while IFS=',' read -r f1 f2 f3 f4 f5 f6 f7 
do 
    echo "$f7 $f6 $f5 $f4 $f3 $f2 $f1" >> output.csv 
done < "$input" 
+1

小改進:在while循環外寫'output.csv'。 –

回答

3

使用awk不僅使處理更容易列的變量數量,但也將是快得多

awk -F, '{ for(i=NF; i>=2; --i) printf "%s ", $i; print $1 }' "$input" > output.csv 
  • -F,告訴awk到輸入分割成以逗號分隔的字段

  • for(i=NF; i>= 2; --i)循環遍歷所有字段索引,從NF(輸入字段的數量)倒數至第2個字段。

  • $i參考字段(列),其基於(1的)索引是i

  • printf "%s "是(隱含的)循環體(你可以將其括在{ ... }爲了清晰),並在手印現場後面有個空格,因爲在你的問題的代碼。
    請注意,printf,不像print確實不是默認情況下會自動附加一個換行符。

  • 最後,在循環之後,print $1打印第一場,接着是換行(\n)來完成輸出線(\nORS,輸出記錄分隔符的默認值)。


如果你需要一個純巴什解決方案慢得多):

Arraysread -a結合是解決方案:

while IFS= read -r line; do # read input line by line 
    # Split line into fields and read into array. 
    IFS=, read -ra fields <<<"$line" 
    # Loop over fields from the back, down to the 2nd. 
    for ((i = ${#fields[@]} - 1; i >= 1; --i)); do 
    printf '%s ' "${fields[i]}" 
    done 
    # Print 1st field and complete line (append line). 
    printf '%s\n' "${fields[0]}" 
done < "$input" > output.csv 

注:

  • 輸出重定向,> output.csv,被施加到整個循環(就像輸入重定向,< "$input"),這是兩個比使用>> output.csv內部環路更簡單和更有效的(在後一種情況下,您還必須事先截取output.csv以確保不會附加任何預先存在的內容)。

  • bash陣列0的基於,而awk係數組索引1啓動。