이 스크립트의 이름은 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
. 인용되지 않았기 때문에 결과는 공백으로 구분되며, 이는 일부 오류 메시지가 나타나는 이유입니다. 분할 단어에도 파일 이름 글로빙이 적용됩니다. 의 출력은 엄격하게 다음과 같습니다.$*
$IFS
ls
ls
보고 있다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