>
배경 :

일부 문자열과 관련된 값을 삽입하는 bash 스크립트 (MacOS 10.9.5)를 작성하고 싶습니다. 스크립트에서 가능한 모든 관련 값을 정의하겠습니다.

예를 들어, 링크 텍스트 yahoo 와 관련된 텍스트를 정의 할 수 있습니다  와이즈 비즈  변수로

www.yahoo.com

접두사 XX_yahoo="www.yahoo.com"  기존 변수와 이름 충돌을 피하기 위해 추가됩니다. 내 스크립트는 모든 발생을 대체하는 것입니다

XX_

with

\MakeLink[yahoo]{}

\MakeLink[yahoo]{www.yahoo.com} 의 대괄호 안에 링크 텍스트를 일치시켜

 기존 변수가 포함 된 매크로 일부 텍스트에 대한 변수가 제공되지 않은 경우 링크 텍스트의 작은 경우를 사용합니다. 따라서

\MakeLink

가되어야한다

\MakeLink[foo bar]{}

<시간>

아래 스크립트는

  • 링크 텍스트에 공백이없고
  • 링크 텍스트 변수가 정의되지 않았습니다
질문 :

링크 텍스트의 가능한 값의 수는 수천 개이며 그 안에 공백이있을 수 있으므로 제 질문은 다음과 같습니다.

<올>
  • 이것이 가장 적합한 방법입니까? 변수에 배열을 사용하는 것이 더 좋습니까?
  • 링크 텍스트에 공백이있는 경우를 어떻게 처리해야합니까? 예를 들어, 할 수 있기를 원합니다

    \MakeLink[foo bar]{Foo Bar}
    
    

    로 교체

    \MakeLink[the google]{}
    
    
  • 참고 사항
    • 좋아, \MakeLink[the google]{www.google.com}. 가 한 번만있다고 가정  한 줄에.
    • 와이즈 비즈  (제목에서와 같이) 대소 문자를 변경하지 않는 단어 목록을 갖도록 매크로를 향상시켜야하지만 나중에 그 문제를 해결할 수 있습니다.
    기존 솔루션의 알려진 문제점 :
    • \MakeLink 와 일치시키는 방법에 문제가 있습니다  선행 백 슬래시가 없어도 일치는 여전히 발생합니다. 테스트 사례에서 첫 번째 단락의 마지막 줄을 참조하십시오.
    • 와이즈 비즈가 있다면  파일에서 그것은 MakeTitleCase 것 같습니다  문제가 있습니다.
    • 링크 텍스트에 공백이있는 경우를 처리하는 방법을 모르겠습니다.
    스크립트
    \MakeLink
    
    
    샘플 입력 파일 :
    ?
    
    
    현재 출력 :
    sed
    
    
    원하는 출력 :

    위에서 만 변경은 #!/bin/bash ## Can't have a backslash in the values of these variables, which is ok for my purposes. XX_yahoo="www.yahoo.com" XX_google="www.google.com" function MakeTitleCase { echo $(echo "$1" | awk '{for(j=1;j<=NF;j++){ $j=toupper(substr($j,1,1)) substr($j,2) }}1') } while read -d $'\n' LINE; do ## Extract target which is the text within the square brackets of "\MakeLink[target]{}" TARGET=$(echo ${LINE} | sed -e 's?\]{}.*??' -e 's?\MakeLink\[??') TEMP=XX_${TARGET} if [ -z "${!TEMP}" ]; then REPLACEMENT=$(MakeTitleCase "${TARGET}") else REPLACEMENT=${!TEMP} fi ## Incorrect handling of leading backslash for the match. echo "${LINE}" | sed "s?\MakeLink\[${TARGET}\]{}?\\\MakeLink\[${TARGET}\]{${REPLACEMENT}}?"; done exit 0 관련 텍스트입니다. 그리고 그 A very popular site on the internet was \MakeLink[yahoo]{} but was surpassed by \MakeLink[google]{} due to its MakeLink[search engine]{}. Due to its dominance \MakeLink[the google]{} has had to deal with \MakeLink[antitrust issues]{}.  선행 백 슬래시가 없어변경하지 않아야합니다.

    A very popular site on the internet was
    \MakeLink[yahoo]{www.yahoo.com} but was surpassed by
    \MakeLink[google]{www.google.com} due to its
    \MakeLink[search engine]{Search Engine}.
    Due to its dominance
    \MakeLink[the google]{The Google} has had to deal with
    \MakeLink[antitrust issues]{Antitrust Issues}.
    
    
    the google
    • 답변 # 1

      choroba와 비슷한 대답 (나는 당신을 보지 않고 이것을 썼다, 맹세한다!), 그러나 하드 코딩없이 제목을 처리한다 :

      #!/usr/bin/perl
      use strict;
      use warnings;
      my %links = (
          yahoo => "www.yahoo.com",
          google => "www.google.com",
      );
      $links{"the $_"} = $links{$_} for keys %links;
      while (<>) {
          s{\\MakeLink\[(.+?)\]\{\}}{
              sprintf "\\MakeLink[%s]{%s}", 
                  $1, 
                  exists $links{$1} ? $links{$1}
                                    : join " ", map {ucfirst lc} split " ", $1;
          }eg;
          print;
      }
      
      

      실행 중 :

      $ perl link.pl input
      A very popular site on the internet was
      \MakeLink[yahoo]{www.yahoo.com} but was surpassed by
      \MakeLink[google]{www.google.com} due to its  
      MakeLink[search engine]{}.
      Due to its dominance
      \MakeLink[the google]{www.google.com} has had to deal with
      \MakeLink[antitrust issues]{Antitrust Issues}.
      
      

    • 답변 # 2

      구조의 펄 :

      #!/usr/bin/perl
      use warnings;
      use strict;
      my %replace = ( yahoo              => 'www.yahoo.com',
                      google             => 'www.google.com',
                      'search engine'    => 'Search Engine',
                      'the google'       => 'The Google',
                      'antitrust issues' => 'Antitrust Issues',
                    );
      while (<>) {
          s/\\MakeLink\[(.*?)\]\{\}/\\MakeLink[$1]{$replace{$1}}/g;
          print;
      }
      
      

      대체 해시 테이블을 만들어 대체에 사용합니다. 최신 bash 버전에서 해시 테이블을 만들 수 있지만 sed에서 직접 사용할 수 없으므로 직접 bash + sed 대응이 없습니다.

    • 답변 # 3

      스크립트를 검토하지 않았지만 인용 문제가 발생하는 몇 곳 (원치 않는 경우 특별한 의미가있는 문자) :

      read -d $'\n' LINE  ( read LINE 를 작성하는 복잡한 방법 ) 백 슬래시 이스케이프를 구문 분석하므로 효과적으로 백 슬래시를 먹습니다. 그것을 read -r LINE 로 . 이 명령은 또한 선행 및 후행 공백을 삭제합니다. 이것을 피하려면 IFS= read -r LINE 로 만드십시오. .

      변수를 sed 스크립트로 대체하고 있습니다. 이러한 변수의 내용은 원하는 방식으로 검색 문자열이나 대체 텍스트가 아닌 sed 스크립트로 구문 분석됩니다. 이것이 ? 의 문제입니다  파일에서 : $TARGET 에 나타날 때 sed는 ? 를 본다 . 이 문제를 해결하려면 sed에서 특수한 모든 문자 앞에 백 슬래시 문자를 추가하십시오 (그리고 정규 표현식과 대체 텍스트에서는 다른 문자를 이스케이프해야합니다!)

      실제로… 내가 쓴 것을하지 마십시오. 나는 무엇이 잘못되었는지 설명하고 있었다. 그러나 드라이버를 사용하여 손톱에 망치를 사용하기 때문에 스크립트를 완전히 다시 작성해야합니다.

      연관 배열이있는 bash를 사용하고 있습니다. 이름이 생성 된 변수를 사용하는 것은 더 나은 방법이 없을 때 편리하지만 적절한 데이터 구조보다 사용하기가 어려운 해킹입니다. Wyzwyz가 아니라면  변수는 실제로 환경에서 와야하고 연관 배열을 사용해야합니다.

      XX_yahoo
      
      
      typeset -A targets targets[yahoo]='www.yahoo.com' 를 사용하여 쉘에서 파일을 한 줄씩 구문 분석하는 동안  큰 파일 (느리게) 또는 사소하지 않은 구문이있는 파일에는 실제로 적합하지 않습니다 (발견 된 것처럼 셸과 외부 도구 사이에서 앞뒤로 작업 할 때 올바르게 구문 분석하기가 어렵습니다) sed와 같은). 귀하의 작업은 awk 스크립트 (또는 다른 답변에 표시된대로 perl)의 주요 자료입니다.

      어쨌든 awk를 사용하려는 경우 awk에서 직접 연관 배열을 정의 할 수도 있습니다.

      테스트되지 않은 코드.

      while read …
      
      
      #!/bin/awk -f BEGIN { targets[yahoo]="www.yahoo.com"; targets[google]="www.google.com"; } function MakeTitleCase(text) { split(text, words); text = ""; for (w in words) { text = text toupper(substr(w,1,1)) substr(w,2) } return text; } /^ *\\MakeLink\[[^][{}]*\]{}/ { target_start = index($0, "[") + 1; target_end = index($0, "]") - 1; target = substr($0, target_start, target_end - target_start); if (target in targets) { replacement = targets[target]; } else { replacement = MakeTitleCase(target); } $0 = substr($0, 1, target_start-1) replacement substr($0, target_end); } 1

  • 이전 performance - 모든 프로그램에서 특정 시간 동안 평균로드
  • 다음 빼기 기호를 tr로 바꾸는 방법