Bash 스크립트에서 다음과 같은 명령을 실행하고 싶습니다.
freebcp <authentication and other parameters> -t "," -r "\r\n"
이 명령은 명령줄에서 직접 실행할 때 예상대로 작동합니다. 그러나 bash 스크립트의 변수에 넣으면 다음과 같은 오류가 반환됩니다.
Msg 20104, Level 3
Unexpected EOF encountered in bcp datafile
Msg 20074, Level 11
Attempt to bulk copy an oversized row to the server
bcp copy in failed
명령이 변수에 배치되고 큰따옴표가 이스케이프되는 경우:
cmd="freebcp ${db_name}.dbo.${table_name} in ${p_file} -S ${server_name} -U ${username} -P ${password} -t \",\" -r \"\r\n\" -c"
`$cmd`
노트:다음을 스크립트에 넣으면 예상대로 작동합니다.
`freebcp ${db_name}.dbo.${table_name} in ${p_file} -S ${server_name} -U ${username} -P ${password} -t "," -r "\r\n" -c`
따라서 인용/이스케이프/확장 문제가 있다는 것을 알고 있지만 해결 방법을 모르겠습니다.
노트 2: 작은따옴표 -t -r 매개변수도 효과가 없습니다.
답변1
짧은 대답: 참조BashFAQ #50: 명령을 변수에 넣으려고 하는데 복잡한 경우에는 항상 실패합니다!.
긴 답변: 쉘은 명령줄을 구문 분석하는 동안, 특히 따옴표를 처리하고 이스케이프 처리한 후에 변수 확장을 수행합니다. 따라서 변수에 따옴표와 이스케이프를 추가하는 것은 명령줄에 직접 따옴표와 이스케이프를 추가하는 것과 다른 효과가 있습니다.
귀하의 답변에 있는 해결책(이스케이프 문자를 두 배로 늘리는 것)은 대부분의 경우 작동하지만 작동할 것이라고 생각하는 이유 때문에 작동하지 않으므로 다소 긴장됩니다. 주문하다:
cmd="freebcp ... -t "," -r "\\r\\n" -c"
큰 따옴표로 묶인 문자열 freebcp ... -t
, 그 뒤에 따옴표가 없는 문자열, ,
큰 따옴표가 붙은 문자열 -r
, 그 뒤에 따옴표가 없는 문자열 '\\r\\n'이 옵니다(따옴표가 없다는 사실은 이중 이스케이프 이유가 필요한 것입니다) , 그 뒤에 큰따옴표로 묶인 문자열 "-c"가 옵니다. 문자열의 일부로 사용하려는 큰따옴표는 문자열의 일부로 처리되지 않고 구분 기호로 처리되어 문자열의 다른 부분이 구문 분석되는 방식을 변경합니다(실제로는 의도한 효과와 거의 반대). 그 이유는 원래 명령에서는 큰따옴표가 실제로 많은 작업을 수행하지 않으므로 해당 역할을 바꿔도 많은 작업을 수행하지 않기 때문입니다. 실제로 실제로 무슨 일이 일어나고 있는지에 대해 오해의 여지가 적기 때문에 내부 항목만 삭제하는 것이 좋습니다. 이것은 작동하지만 깨지기 쉽습니다. 작동하는 유일한 이유는 실제로 큰따옴표가 필요하지 않기 때문입니다. 그리고 상황(예: 공백이 포함된 비밀번호 또는 파일 이름)이 발생하는 경우 인용문이 필요한 경우, 그렇다면 당신은 곤경에 처한 것입니다.
더 나은 옵션이 몇 가지 있습니다.
명령을 변수에 전혀 저장하지 말고 직접 실행하십시오. 명령을 저장하는 것은 까다롭기 때문에(당신이 발견한 바와 같이), 정말로 필요하지 않다면 하지 마십시오.
기능을 사용하세요. 동일한 명령을 반복적으로 실행하는 등의 작업을 수행하는 경우 이를 함수로 정의하고 사용하세요.
loaddb() { freebcp "${db_name}.dbo.${table_name}" in "${p_file}" -S "${server_name}" -U "${username}" -P "${password}" -t \",\" -r \"\r\n\" -c" } loaddb
큰따옴표를 사용했음을 참고하세요.모두변수 참조 수 - 공백, 와일드카드 또는 쉘이 인식하지 못하는 기타 항목이 포함된 경우 일반적으로 좋은 스크립트 위생입니다.하다변수 값을 구문 분석합니다.
일반 변수 대신 배열을 사용하십시오. 이 작업을 올바르게 수행하면 각 명령 인수가 배열의 별도 요소로 저장됩니다. 그런 다음 관용구를 사용하여
"${arrayname[@]}"
전체를 가져올 수 있습니다.cmdarray=(freebcp "${db_name}.dbo.${table_name}" in "${p_file}" -S "${server_name}" -U "${username}" -P "${password}" -t \",\" -r \"\r\n\" -c") "${cmdarray[@]}"
여기서도 큰따옴표를 많이 사용한다는 점에 유의하세요. 여기서는 배열 요소가 배열에 저장된 값의 일부가 아니라 올바르게 정의되었는지 확인하는 데 사용됩니다. 또한 모든 쉘에서 배열을 사용할 수 있는 것은 아닙니다. bash나 zsh 또는 이와 유사한 것을 사용하고 있는지 확인하십시오.
몇 가지 최종 참고 사항: 사용 시:
`somecommand`
백틱은 생각대로 작동하지 않으며 실제로 잠재적으로 위험합니다. 그들이 하는 일은 명령을 실행하고, 그 출력을 캡처하고, 해당 출력을 다음과 같이 실행하는 것뿐입니다.다른주문하다. 명령이 아무것도 인쇄하지 않는지는 중요하지 않지만, 뭔가를 인쇄한다면 출력은 유효한 명령이 아닐 가능성이 높습니다. 백틱을 잃어 버리십시오.
마지막으로, 비밀번호를 명령 인수로 전달하는 것은 안전하지 않습니다. 프로세스 테이블(즉, 명령이 ps
볼 수 있는 위치)에 명령 인수를 게시하고 공개 위치에 비밀번호를 게시하는 것은 매우 나쁜 생각입니다. freebcp
이 외에는 딱히 대안이 없을 것 같지만,패치를 찾았습니다이렇게 하면 표준 입력에서 비밀번호를 읽게 됩니다( echo "$password" | freebcp -P - ...
--note 이것은 echo
쉘 내장이므로 해당 인수는 프로세스 테이블에 표시되지 않습니다). 나는 패치의 정확성, 보안 등에 대해 어떠한 주장도 하지 않습니다(특히 패치가 꽤 오래되었기 때문에). 그러나 제가 당신이라면 확인해 볼 것입니다.
답변2
백슬래시 이스케이프\n\r성공한 것 같다
cmd="freebcp ${db_name}.dbo.${table_name} in ${p_file} -S ${server_name} -U ${username} -P ${password} -t "," -r "\\r\\n" -c"