Bash 스크립트 내에서 sed 명령줄 매개변수 및 변수 사용

Bash 스크립트 내에서 sed 명령줄 매개변수 및 변수 사용

여러 명령줄 인수가 필요한 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;"

답변1

원래 셸 파이프라인의 모든 명령을 columns=단일 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"
)

# . . .

나는 가독성을 위해 여러 줄 형식을 선호합니다. 원래 문장은 한 줄에 불과하지만 훨씬 덜 효율적이고 읽기가 더 어렵다고 생각합니다. 욤드

이제 newlines로 구분된 변수에 저장된 입력 파일(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나는 쉘 배열을 사용하지 않기 때문에 배열 루프를 테스트하지 않았습니다 . 위의 반복 방법은 $columns비교적 일반적이고 전통적인 방법입니다. Arrays는 확장이며 모든 쉘에서 사용할 수 있는 것은 아닙니다.

에 할당한 후에 cut_cols는 동일하게 반복할 수 있습니다 $columns.

원본 파일 데이터가 포함된 새 헤더를 보내려면 새 헤더를 인쇄한 다음 원본 파일의 첫 번째 줄을 제외하고 모두 인쇄하세요. 두 명령의 출력을 마치 하나의 프로그램인 것처럼 함께 리디렉션할 수 있도록 명령 그룹( {및 사이)에서 이 작업을 수행합니다.}

다음은 원래 헤더 줄 없이 완전한 원시 텍스트 파일을 생성하지만 생성한 헤더 줄을 포함하여 다음 stdin으로 보냅니다 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;"

답변2

나는 이 질문을 정말로 이해하지 못한다.(구체적으로 파일의 열 헤더 행만 편집하는 이유 - 나중에 식별하는 데 사용되는 모든 행은 어떻게 되나요?), 하지만 이 부분은 의미가 있습니다.

        #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.

알겠어요. 다음은 sed파일에서 특정 필드를 추출하기 위한 몇 가지 팁 입니다 .

printf 'one    two three' |
sed    's|[^ ]*||5'

one     three

이상해 보이는데요, 그렇죠? 여기서 sed5번째는 삭제됐어요가능한길이에 상관없이 공백이 아닌 문자 시퀀스를 단일 필드로 계산하는 공백이 아닌 문자 시퀀스 - 길이가 0인 시퀀스를 포함합니다. 그래서하나은 첫 번째 필드이고, 다음은 다음 공백과 그 뒤 공백 사이의 빈 문자열입니다. 필드 3과 4도 마찬가지이며, 다섯 번째 필드는 공백 4개입니다. 나도 알아, 힘든 일이야.

printf 'one    two three' |
sed    's|[^ ][^ ]*||2'

one     three

나는틀림없이각 필드는 공백이 아닌 문자 하나 이상과 일치하므로 sed다른 프로그램과 유사하게 작동합니다. 하지만 정규식의 가장 큰 장점은 특히 편집에 적용할 때 출력 동작을 매우 구체적으로 맞춤화할 수 있으며 빈 문자열을 처리하는 것은 그 일부일 뿐이라는 것입니다.

답변3

알았어, 알겠다. 일부 사람들을 혼란스럽게 하는 문제는 헤더 행을 가져오고 필드 이름의 이상한 부분을 편집한 다음 이를 파일에 다시 추가하는 방법입니다.

내가 한 일은 다음과 같습니다.

  1. 머리글 행을 편집하고 변수에 할당합니다.
  2. 항상 헤더 줄과 텍스트 파일의 나머지 부분을 분리하세요.

이 솔루션은 주로 Vertica 테이블의 로더인 스크립트의 특성에 기인합니다. 헤더 행과 파일에서 동일한 필드를 제거하기만 하면 다시 하나의 파일이 되어도 문제가 되지 않습니다. 제가 가장 하고 싶은 일은 편집된 제목을 원래 내용과 다시 결합하여 올바른 제목 줄이 포함된 텍스트 파일을 디렉터리에 저장할 수 있도록 하여 제목 줄과 내용을 별도로 잘라낼 필요가 없도록 하는 것입니다. 그런데 이렇게 따로 잘라서 나왔는데,

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
            ind=$(($i+1))
            cut_cols="$cut_cols,$ind"
    fi
done

cut_cols=$(echo $cut_cols | sed s/^,//g)
columns=$(echo "$columns" | cut -f "$cut_cols")
cut -f ${cut_cols} ${1}>member_temp.txt
sed -i 1d member_temp.txt

열에 대한 변수를 유지하기로 한 결정은 이 스크립트를 로더로 사용함으로써 이루어졌습니다. Vertica에서 테이블을 생성하려면 각 필드와 해당 데이터 유형을 식별하는 문이 필요합니다. 이를 위해 create 문의 구문에 사용될 문자열의 필드와 데이터 유형으로 변수를 채우는 일부 if 문을 통해 열 변수(헤더 행)를 실행합니다.

그런 다음 앞서 생성한 테이블에 member_temp.txt를 로드했습니다. 헤더 행이 없다는 것은 중요하지 않습니다. 테이블에 저장하는 것을 원하지 않기 때문에 어쨌든 삭제할 것이기 때문입니다.

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

관련 정보