Bash

在 sed 內部 Bash 腳本中使用命令行參數和變數

  • November 10, 2015

我有一個 bash 腳本,它需要一堆命令行參數。在這種情況下,唯一重要的是第一個 $1,它是一個文本文件。

標題很長,下面是一些欄位的範例。

COL0___LINE_NUMBER
COL1_AFF_ID
COL2_FULL_NAME
COL3_ADDRESS
BDID
BEST_STATE
COL48_LATITUDE   
COL49_LONGITUDE

我需要更改標題行,我可以使用下面的程式碼來完成。這確實完成了我想要的,但是考慮到這是我第一次編寫 bash 腳本,歡迎保留如下輸出中的變數的任何風格更改等。

columns=`cat $1 | head -1 |sed 's/-/_/g' |  sed 's/ /_/g' |
   sed 's/COL[0-9]\+_BDID/DROP_BDID/g' | sed 's/COL[0-9]\+_//g' |
   tr '\t' '\n' | tr  "[:lower:]" "[:upper:]"`

注意:換行符的製表符的格式純粹是為了在回顯列標題時嘗試美學。這既是為了我的可讀性,也是為了回顯 vertica create table 語句的腳本使用者。

無論如何,現在我想讓列變數成為我的文本文件的標題行,以便我可以在腳本中使用新版本。所以,我想要完整的原始文本文件**,沒有**它的原始標題行,以及我創建的那個,例如,以下是指我的文件的編輯版本,

col_arr=($columns)
cut_cols = ""

for i in ${!col_arr[@]}; do
   if [[ "${col_arr[$i]}" =~ ^(__LINE_NUMBER|CONFIDENCE|DROP_BDID|LINE_NUMBER|ZIP9|ZIP9|ZIP9MATCH)$ ]]; then
           echo "$i"
           #haven't written yet, but this will add to cut_cols so that 
           #I can remove the above listed columns in the text file 
           #based on their index.
   fi
done
/opt/vertica/bin/vsql -U ${4} -w ${5} -h ${database} \
   -c "copy $schema.$table from STDIN delimiter E'\t' direct no escape;"

我們可以將原始columns=shell 管道中的所有命令組合到一個sed腳本中。此sed腳本僅修改輸入的第一行,然後退出。以下內容與原始問題中的內容完全相同:columns=

columns=$(
   sed '               
       1 {                                   # execute block on line 1
           s/-/_/g     
           s/ /_/g     
           s/COL[0-9]\+_BDID/DROP_BDID/g
           s/COL[0-9]\+_//g
           s/\t/\n/g   
           y/abcdefghijklmnopqrstuv/ABCDEFGHIJKLMNOPQRSTUV/
           q                                 # quit after line 1
       }
   ' "$1"
)

# . . .

為了便於閱讀,我更喜歡多行格式。儘管最初的聲明是一行,但效率要低得多,而且在我看來,更難閱讀。yomd

現在您已經從輸入文件 (arg 1) 中獲得了標頭,這些標頭儲存在columns由換行符分隔的變數中。$columns您可以使用循環遍歷字元串,這將用換行符for分隔列名:cut_cols

cut_cols="$(
   for col in $columns
   do
       case $col in
       (*__LINE_NUMBER*|*CONFIDENCE*|*DROP_BDID*|*LINE_NUMBER*|*ZIP9*|*ZIP9MATCH*)
               echo "$col"
               ;;
       esac
   done
)"

根據您的喜好,這會做同樣的事情:

cut_cols=
for col in $columns
do
   case $col in
       (*__LINE_NUMBER*|*CONFIDENCE*|*DROP_BDID*|*LINE_NUMBER*|*ZIP9*|*ZIP9MATCH*)
           cut_cols="$cut_cols $col"
           ;;
   esac
done
cut_cols=$(echo "$cut_cols" | sed 's/^ *//; s/ /\n/g')

我沒有測試你的數組循環,cut_cols因為我不使用 shell 數組。上面的迭代方法$columns是比較通用和傳統的方法。 Arrays 是一個擴展,並非在每個 shell 中都可用。

分配給 之後cut_cols,您可以像 一樣對其進行迭代$columns

要發送帶有原始文件數據的新標題,請列印新標題,然後列印除原始文件第一行之外的所有內容。在命令組(介於{和之間})中執行此操作,這樣您就可以將兩個命令的輸出重定向到一起,就好像它們是一個程序一樣。

以下生成完整的原始文本文件,沒有原始標題行,並使用您創建的文件,並將其發送到stdinof vsql

# . . .

{                                   # start command group

   echo "$columns" | tr '\n' '\t'; # print with tabs instead of newlines
   echo                            # add newline record separator
   sed 1d "$1"                     # print all but 1st line of "$1"

} |                                 # pipe as one file to vsql

/opt/vertica/bin/vsql -U ${4} -w ${5} -h ${database} \
   -c "copy $schema.$table from STDIN delimiter E'\t' direct no escape;"

引用自:https://unix.stackexchange.com/questions/241372