문자열을 명령 끝으로 이동

문자열을 명령 끝으로 이동

재사용하고 싶은 주문을 만들었지만 함수로 저장하기에는 임시 수정에 너무 취약한 경우가 종종 있습니다. 이러한 명령에는 내부 깊숙이 묻혀 있는 파일 이름과 같은 일부 주요 변수 구성 요소가 포함되는 경우가 많습니다. 이 구성 요소를 명령 끝 부분으로 이동하고 싶습니다.

예를 들어, 내 최신 부두는 INSERTdiff 파일의 모든 새 문에 대한 테이블 정의를 인쇄합니다.

for T in $(grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" foo.diff | sort -u) ; do docker-compose exec mysql mysqldump --no-data some_database $T | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT" | sed "s/ COMMENT .*,$/,/" | sed "s/CONSTRAINT \`\w*\` //" | sed "s/^) ENGINE.*;/);/" ; done

가독성을 위해 형식 지정:

for T in $(grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" foo.diff | sort -u)
  do
  docker-compose exec mysql mysqldump --no-data some_database $T
    | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT"
    | sed "s/ COMMENT .*,$/,/"
    | sed "s/CONSTRAINT \`\w*\` //"
    | sed "s/^) ENGINE.*;/);/"
done

나는 나중에 이라는 파일이 아닌 파일에 대해 이 명령을 다시 사용하고 싶을 것이므로 foo.diff명령이 파일 이름으로 끝나기를 원합니다. 나의 첫 번째 성향은 모든 것을 함수로 감싸고 파일 이름을 $1 매개변수로 전달하는 것입니다.

그러나 실행할 때 더 조정할 가능성이 높습니다. 여기에 sed를 추가하세요. 어쩌면 거기에 약간의 어색함도 있을 것입니다. 따라서 Ctrl-P다시 실행해도 여전히 전체 명령이 CLI에 있기를 원합니다. 그래서 변수를 사용하기로 결정했습니다.

$ FILENAME=diff-03-04.sql

오늘은 각 주문에 대해 동일한 파일을 사용할 것이므로 이 특정 예에 적합하지만 명령의 끝 부분을 조정할 수 있는 다른 예도 있습니다. 그래서 이거:

$ for Q in $(foo Torvalds bar) ; do baz $Q ; done

다음과 유사하지만 반드시 동일하지는 않습니다.

$ for Q in $(foo SOME_MAGIC_HERE bar) ; do baz $Q ; done < Torvalds

답변1

스크립트나 함수의 힘을 잘못 이해하고 계신 것 같습니다. 개인적으로 저는 스크립트가 독립적이고 어떤 대화형 셸을 사용하더라도 사용할 수 있기 때문에 스크립트를 선호합니다. 하지만 함수는 똑같은 일을 할 수 있습니다. 나에게 있어 시스템 전체 스크립트는 에 들어가고 /usr/local/bin개인(정크) 스크립트는 에 들어갑니다 ~/bin. 둘 다 내 안에 있어요 $PATH.

디렉토리를 생성합니다 ~/bin. 이것을 $PATH( export PATH="$PATH:$HOME/bin")에 추가하세요. 이제 이 디렉터리에 있는 실행 가능한 스크립트를 새 명령으로 사용할 수 있습니다.

당신의 예를 들어 보겠습니다. 사용할 때 파일 이름을 선택하기를 원하므로 이를 스크립트의 첫 번째 인수로 만들어 보겠습니다.

파일 만들기 ~/bin/tables:

#!/bin/bash
file=$1
for T in $(grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" "$file" | sort -u)
  do
  docker-compose exec mysql mysqldump --no-data some_database "$T"
    | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT"
    | sed "s/ COMMENT .*,$/,/"
    | sed "s/CONSTRAINT \`\w*\` //"
    | sed "s/^) ENGINE.*;/);/"
done

스크립트를 실행 가능하게 만들면 chmod a+x ~/bin/tables이제 새로운 명령이 생성됩니다.

tables foo.diff
tables another.diff

답변2

여기 있는 모든 사람들은 다른 답변과 의견에서 훌륭한 조언을 제공했습니다. 내가 찾은 가장 좋은 방법은 명령을 함수로 래핑하고 해당 함수를 단일 명령으로 실행하는 것입니다.

$ _() { echo $1; } && _ beer
beer
$

또한 for T in $()구문을 cmd | while readKusalananda가 제안한 구문으로 대체했습니다. 따라서 최종 구문은 다음과 같습니다.

_() { grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" $1 | sort -u | while read -r T ; do docker-compose exec mysql mysqldump --no-data some_database $T | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT" | sed "s/ COMMENT .*,$/,/" | sed "s/CONSTRAINT \`\w*\` //" | sed "s/^) ENGINE.*;/);/" ; done } && _ foo.diff

가독성을 위해 형식 지정:

_() {
  grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" $1
    | sort -u
    | while read -r T ;
      do
      docker-compose exec mysql mysqldump --no-data some_database $T
        | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT"
        | sed "s/ COMMENT .*,$/,/"
        | sed "s/CONSTRAINT \`\w*\` //"
        | sed "s/^) ENGINE.*;/);/"
    done
}
&& _ foo.diff

이 방법은 필요한 명령의 어느 부분이든 조정할 수 있는 기능을 유지하지만 명령 자체에서 따옴표를 이스케이프 처리하지 않고도 매개변수(이 경우 파일 이름)를 쉽게 변경할 수 있습니다.

관련 정보