
여러 명령줄 인수를 사용하는 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"
)
# . . .
나는 가독성을 위해 여러 줄 형식을 선호합니다. 원래 문장은 한 줄로 되어 있었지만 훨씬 덜 효율적이었고 제 생각에는 읽기가 더 어려웠습니다. 욤드
이제 줄 바꿈으로 구분된 변수에 저장된 입력 파일(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
보다 보편적이고 전통적인 방법입니다. Array
s는 확장이며 모든 쉘에서 사용할 수 있는 것은 아닙니다.
에 할당한 후에 cut_cols
는 와 동일하게 반복할 수 있습니다 $columns
.
원본 파일 데이터와 함께 새 헤더를 보내려면 새 헤더를 인쇄한 다음 원본 파일의 첫 번째 줄을 제외하고 모두 인쇄하세요. 명령 그룹( {
과 사이 }
)에서 이 작업을 수행하면 두 명령의 출력을 마치 하나의 프로그램인 것처럼 함께 리디렉션할 수 있습니다.
다음은 원래 헤더 행 없이 사용자가 만든 전체 원본 텍스트 파일을 생성하여 of 로 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
이상해 보이는데요, 그렇죠? 여기서는 sed
5번째를 제거합니다.가능한공백이 아닌 문자의 시퀀스는 공백이 아닌 문자의 모든 길이 시퀀스를 단일 필드로 계산하여 길이가 0인 시퀀스를 포함하도록 작동합니다. 그래서하나은 첫 번째 필드이고, 다음은 다음 공백과 그 뒤의 공백 사이의 null 문자열입니다. 필드 3과 4도 마찬가지이고, 다섯 번째 필드는 4개의 공백입니다. 꽤 형편없군요.
printf 'one two three' |
sed 's|[^ ][^ ]*||2'
one three
거기에는명확한필드당 공백이 아닌 문자 하나 이상과 일치하므로 sed
다른 프로그램과 비슷하게 동작합니다. 그러나 정규식의 편리한 점은 특히 편집에 적용할 때 출력 동작을 매우 구체적으로 맞춤화할 수 있고 널 문자열 처리가 모두 그 일부일 뿐이라는 것입니다.
답변3
좋아, 그래서 알아냈어. 일부 사람들을 혼란스럽게 했던 질문은 어떻게 헤더 행을 가져오고, 필드 이름의 일부 이상한 부분을 편집하고, 파일 앞에 다시 추가하는가였습니다.
내가 한 일은 다음과 같습니다.
- 헤더 행을 편집하고 변수에 할당합니다.
- 머리글 행과 나머지 텍스트 파일을 항상 별도로 유지하십시오.
이 솔루션은 주로 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;"