csplit 및 sed를 사용하는 스크립트를 이해하도록 도와주세요.

csplit 및 sed를 사용하는 스크립트를 이해하도록 도와주세요.

참조 관리자 Zotero에서 노트를 내보내는 쉬운 방법을 원합니다. 여러 개의 메모를 선택하고 빈 텍스트 파일로 드래그하는 것으로 시작합니다. 또한 메모의 "원자성"을 달성하고 싶기 때문에 개별 메모가 포함된 결과 텍스트 파일을 점선으로 구분된 섹션으로 분할해야 합니다. 그런 다음 각 댓글에 부여한 제목을 사용하여 새 파일의 이름을 지정하고 싶습니다. 즉, 각 섹션의 첫 번째 줄로 이름을 바꿉니다. 이 새 파일을 마크다운 파일로 저장하고 싶습니다.

제가 작성한 스크립트는 웹상의 기여자들이 각 기능에 대해 제안한 내용으로 구성되어 있습니다. 나와 비슷한 사용 사례를 가진 동료와 스크립트를 공유하기 전에 스크립트의 명령을 올바르게 이해했는지 확인하려고 노력합니다. "head" 명령에서 "$f" 주위에 따옴표가 필요하다는 점에 대한 나의 이해(Giles의 답변을 다른 질문에 읽음 - 아래 참조 링크 참조)가 잘못된 것 같습니다. 따옴표 없이 스크립트를 시도했지만 동일한 결과를 얻었습니다. 과제 오른쪽에 "$f"가 나오므로 큰따옴표가 필요하지 않다는 것이 맞나요? 필요하지 않을 때 기억하는 것보다 기본적으로 큰따옴표를 사용하는 것이 더 쉽기 때문에 존재하는 것일까요? 추가 설명을 주시면 대단히 감사하겠습니다.

Notes_test.txt의 입력 파일 예는 다음과 같습니다.

This is note 1

It has some notes

--------------------------------------------------

This is note 2

It has some more notes

출력은 두 개의 파일이어야 합니다.

This is note 1.md
This is note 2.md

명령줄에서 사용하는 스크립트는 다음과 같습니다.

csplit Notes_test.txt -f_ -z -b'%03d.md' /--------------------------------------------------/1 {*} && sed -i '/./,$!d' *.md && for f in *.md
    do
    f1=$(head -n1 "$f")
    mv -n "$f" "$f1.md"
    done

이것은 지금까지 명령에 대한 나의 이해입니다.

-fPREFIX 출력 파일 이름 접두사로 PREFIX를 사용합니다. 이 경우 밑줄은 "_"로 지정되는데, 제 생각에는 이는 단지 자리 표시자일 뿐입니다.

-z는 길이가 0인 출력 파일의 생성을 억제합니다. 그렇지 않으면 csplit이 원본 파일을 분할하여 각 실행이 끝날 때 빈 파일을 생성하기 때문에 이것이 필요하다고 생각합니다.

-bSuffix SUFFIX를 출력 파일 이름 접미사로 사용합니다. 이 경우: "md"

%03d는 파일 이름의 자리 표시자로 3자리 숫자를 사용합니다. FelixJN의 제안에 따라 3 앞에 0을 추가했습니다.

/------------------------------------------------- -/1은 "-" 줄 아래의 두 줄을 나누기 위한 구분 기호를 지정합니다(0부터 계산).

{*}는 bash에게 파일이 끝날 때까지 분할을 실행하도록 지시합니다. Felix가 지적했듯이 "{n}"은 수행할 분할 횟수입니다. 이 경우 "*"는 가능한 한 많이 수행한다는 의미입니다.

&&는 이전 명령이 완료된 후 다음 명령을 실행한다는 의미입니다.

sed -i는 sed에게 특정 접미사 '/./,$!d'가 있는 파일에서 작동하도록 지시합니다. 이는 "파일 시작 부분의 빈 줄 삭제"를 의미합니다. 설명을 주신 Felix에게 다시 한 번 감사드립니다. sed의 작업 범위: " ."는 모든 문자를 의미하므로 문서에 나타나는 첫 번째 문자를 지정합니다. 빈 줄에는 문자가 없으므로 범위를 정의한 후 음수 기호 "!"를 적용해야 합니다. 범위는 문자열 "start"와 "end" 사이에 명령을 적용하기 위해 /"start"/,/"end"/ 패턴으로 정의됩니다. $는 마지막 줄을 참조하므로 범위는 문서에서 비어 있지 않은 모든 줄입니다. 부정을 적용하려면 "NOT"을 의미하는 "!"를 사용하십시오. 즉, sed에게 이전 범위에서 반대 값을 선택하라고 지시하십시오. 이 경우 첫 번째 줄 앞의 모든 줄에는 모든 문자가 포함될 수 있습니다. 그런 다음 "d"는 이 줄을 삭제합니다.

*.md는 "접미사 .md가 있는 모든 이름"을 의미합니다.

f1=$(head -n1 "$f")는 다음을 의미합니다: f1을 파일의 첫 번째 줄로 정의합니다("head"는 "첫 번째 줄"을 의미함). 이는 새 파일 이름(접미사 제외)에 대한 자리 표시자(스크립트의 다음 줄)가 될 변수 기호 "$"를 사용하여 "f1"을 정의함으로써 수행됩니다. "head"는 일반적으로 각 파일의 처음 10줄을 출력하는 bash 명령입니다. head [OPTION]... [FILE]... 옵션 -n1은 한 줄만 출력하도록 지정합니다. 여기서 "$f"는 특정 파일을 지정하는 것이 아니라 "모든 파일"을 지정합니다. 공백이 무시되도록 "$f" 주위에는 따옴표가 필요합니다(그렇지 않으면 $f는 공백을 필드 구분 기호로 사용하고 파일을 추가로 분할합니다. 아래 참조 링크 참조).

mv -n "$f" "$f1.md"는 각 파일의 이름을 "f1.md"로 바꾸는 것을 의미합니다.

bash 명령 "mv"는 옵션과 인수를 사용합니다: mv [OPTION]... [-T] SOURCE DEST 즉, "SOURCE를 DEST로 이름 바꾸기"입니다. -n 옵션은 --no-clobber "기존 파일을 덮어쓰지 않음"을 나타냅니다. 이는 단지 동일한 첫 줄(주석)이 있는 파일이 존재하지 않도록 하기 위함이라고 생각합니다.

바라보다https://www.tutorialspoint.com/unix_commands/csplit.htmUNIX와 유사한 작업을 위한 coreutils는 다음 위치에 있습니다.https://www.gnu.org/software/coreutils/manual/coreutils.pdf 그리고https://www.howtoforge.com/linux-csplit-command/Q2.정규식을 사용하여 파일을 분할하는 방법은 무엇입니까? 그리고공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까? 언제 큰따옴표가 필요합니까?

답변1

이해하신 부분에는 문제가 없을 것 같으니 이 sed부분에 집중하겠습니다.

범위

sed다음과 같이 an을 a (즉, 줄의 첫 번째 항목) 로 바꾸면( s대체) 예를 들어 11번 줄부터 20번 줄까지 범위 내에서 명령을 실행할 수 있습니다.AB

sed '11,20s/A/B/'

/start/,/end/문자열과 사이에 명령을 적용하기 위해 패턴 일치를 통해 범위를 정의할 수도 있습니다 .startend

귀하의 경우에는 /./,$.

A는 .모든 문자를 의미하며, 빈 줄에는 문자가 없으므로 줄이 비어 있지 않은 경우에만 적용됩니다. $마지막 줄만 인용되므로 전체 문서에 대해 이 작업을 수행하지만 시작 부분의 빈 줄은 건너뜁니다.

이제 !작동합니다. 이는 "NOT"을 의미합니다. 즉, 이전 범위에서 반대 값을 선택합니다. 이 경우 첫 번째 줄 앞의 모든 줄에는 문자가 있습니다.

d그런 다음 이 줄을 삭제하세요.


'{*}'의 또 다른 의견입니다 csplit. '{n}'는 수행할 분할 수이며 별표는 단순히 가능한 한 많은 분할을 의미합니다. 또한 5번만 분할할 수도 있습니다.

%3d%03d제로 패딩된 세 자리 숫자를 표시하는 데 사용하지 않는 것이 좋습니다 . 이렇게 하면 정렬이 더 쉬워집니다.

관련 정보