내 스크립트를 어떻게 디버깅합니까?

내 스크립트를 어떻게 디버깅합니까?

이 스크립트의 이름은 hello입니다.

for i in $(ls $*);do
    x=$(echo $(basename $i".md"));
    pandoc $i -t "latex" -o $x.pdf;
done

내가 이걸 쓸 때

$ ./hello *bye.md

이 오류

ls: cannot access 'test': No such file or directory  
ls: cannot access 'de': No such file or directory  
ls: cannot access 'bye.md': No such file or directory
basename: extra operand ‘bye.md’  
Try 'basename --help' for more information.  
./hello: 2: ./hello: pandoc: not found  
basename: extra operand ‘.md’  
Try 'basename --help' for more information.  
./hello: 2: ./hello: pandoc: not found  

내 스크립트 hello가 제대로 작동하지 않는 이유를 이해할 수 없습니까?

그리고 다음 명령은 올바른 디렉토리에 pdf를 생성하지 않습니다.

$ ./hello */test.md  

답변1

set -x실행 중인 명령을 정확히 보여주는 명령을 사용하여 스크립트를 디버깅할 수 있습니다. 를 사용하여 이 모드를 비활성화할 수 있습니다 set +x. 이를 통해 존재하지 않는 파일에서 루프를 실행하다가 basename잘못 실행되는 것을 볼 수 있습니다.

또한:

  • ls의 출력을 구문 분석하지 마십시오.. for i in "$@"; do그것은 당신에게 아주 잘 어울릴 것입니다.

  • basename확장자는 별도의 인수로 필요하므로 다음과 같이 작성해야 합니다 basename $i ".md". 파일 이름을 포함하는 변수와 확장자 사이에 공백이 없습니다.

  • 변수에 공백이 포함되어 있으면 인용 부호로 묶어야 합니다.실제로basename "$i" .md하고pandoc "$i" -t "latex" -o "$x".pdf

  • 이것은 echo중복됩니다.x=$(basename "$i" .md)

답변2

이 스크립트에는 숙련된 스크립트 작성자에게 분명하게 드러나는 많은 문제가 있습니다. 하지만 귀하의 질문은 "어떻게 디버깅합니까?"입니다.

첫째, 한 줄의 텍스트가 아닌 명확하고 읽기 쉬운 형식으로 스크립트를 작성하십시오.

#!/bin/bash
for i in $(ls $*) ; do 
    x=$(echo $(basename $i".md"))
    pandoc $i -t "latex" -o $x.pdf
done

내가 추가한 것을 알 수 있습니다 #!/bin/bash. 이렇게 하면 bash스크립트가 강제로 사용됩니다. 그렇다면 디버깅하는 방법은 무엇입니까?

$i루프 변수는 루프를 통과할 때의 생각을 포함합니까? 에코는 이를 명확하게 보여줍니다. $x로도 동일한 작업을 수행할 수 있습니다.

#!/bin/bash
for i in $(ls $*) ; do 
    echo "LOOP VARIABLE $i"
    x=$(echo $(basename $i".md"))
    echo "AND X IS $x"
    pandoc $i -t "latex" -o $x.pdf
done

이것이 디버깅의 기본 방법입니다.

이제 스크립트, 출력 등으로 돌아갑니다. test de bye.md디렉토리에 ""라는 파일이 있습니다. 그렇죠?

좋아요 처음부터 시작합니다(실제로는 이것이 빠졌지 @!만 문제가 있는 부분입니다). 나는 이것을 위해 여러 번 꾸짖 ls었습니다.여기이유를 읽을 수 있습니다.

$*와 의 차이점에 관심이 있으실 수도 있습니다 $@. 그건 여러분의 Google 능력에 맡기겠습니다.

건축물이 x=$(echo $(basename $i".md"))이상해요. 특히 .md파일 이름 끝에서 이미 스크립트를 호출하는 경우에는 여기서 무엇을 달성하려는지 이해하지 못합니다 .

공백이 포함된 매개변수를 인용할 수도 있습니다. 예를 들어 test de bye.md, $i에 가 포함되어 있으면 ls $i`ls는 3개의 매개변수와 함께 호출됩니다.

  • 시험
  • 안녕히 계세요.md

ls "$i"교정을 위해 매개변수를 사용 하는 동안 ls:

  • 안녕 테스트.md

이렇게 하면 완전히 다른 결과가 생성됩니다.

또 다른 질문: pandoc시스템에 이 소프트웨어가 설치되어 있습니까? 오류 메시지는 이것이 사실이 아님을 나타냅니다. 로 확인하세요 which pandoc.

Fortran을 배우신 분들(제가 그만큼 늙었군요!)을 아시는 분들에게 i는 정수입니다. 하지만 설명이 포함된 이름을 사용할 수도 있으므로 향후 스크립트 유지 관리가 더 쉬워집니다.

따라서 스크립트는 다음과 같습니다.

#!/bin/bash
for infile in "$@" ; do
    outfile=${infile%.md}.pdf
    pandoc "$infile" -t latex -o "$outfile"
done

또는 그런 것.

답변3

귀하의 루프:

for i in $(ls $*);do
    x=$(echo $(basename $i".md"));
    pandoc $i -t "latex" -o $x.pdf;
done

수정된 버전:

#!/bin/sh

for pathname do
    pandoc "$pathname" -t "latex" -o "$( basename "$pathname" .md ).pdf"
done

노트:

  • 명령줄 인수 를 반복하려면 do 는 의 첫 번째 문자와 연결된 위치 인수입니다 for variable do ...; done. 인용되지 않았기 때문에 결과는 공백으로 구분되며, 이는 일부 오류 메시지가 나타나는 이유입니다. 분할 단어에도 파일 이름 글로빙이 적용됩니다. 의 출력은 엄격하게 다음과 같습니다.$*$IFSlsls보고 있다at (파일 이름은 명령줄에서 전달되므로 파일 이름을 나열할 이유가 없습니다).

  • $(echo $(some-utility))더 정확하게는 로 작성됩니다 $(some-utility). 필요하지 않음 echo이 소개됩니다.흥미로운어떤 경우에는 특정 유틸리티가 백슬래시 등을 출력할 때 이것이 영향을 미칩니다. 또한 출력 시 토큰화 및 파일 이름 글로빙이 발생합니다.

  • 나는 중간 변수를 사용하지 않기로 결정했습니다. 어쨌든 한 번만 사용하면 됩니다. 또한 파일 이름 접미사를 제거하고 싶어한다고 추측하여 .md루프에 대해 더 설명적인 변수 이름을 사용했습니다. 하위 디렉터리를 포함할 수 있는 경로 이름을 얻을 수 있더라도 현재 디렉터리의 파일에 쓰는 것처럼 보입니다 somedir/file.md.

원본 파일과 동일한 디렉터리에 있는 파일에 쓰는 변형 .md:

#!/bin/sh

for pathname do
    pandoc "$pathname" -t "latex" -o "${pathname%.md}.pdf"
done

답변4

루프 프로그램 출력 작업은 for힘든 작업이 될 수 있습니다. 루핑이 while더 쉬운 경향이 있습니다. 또한 나는 라인 2가 당신이 생각하는 것을 하고 있다고 생각하지 않습니다. 이 시도:

ls $* | while read infilename; do
    outfilename=$(echo $infilename | sed 's/.md/.pdf/')
    pandoc $infilename -t "latex" -o ${outfilename}.pdf;
done

관련 정보