공간을 이해하다

공간을 이해하다

다음은 Ishmael Smyrnow가 macOS 아이콘 캐시를 지우기 위해 작성한 한 줄짜리 bash 스크립트입니다.

sudo rm -rfv /Library/Caches/com.apple.iconservices.store; sudo find /private/var/folders/ \( -name com.apple.dock.iconcache -or -name com.apple.iconservices \) -exec rm -rfv {} \; ; sleep 3;sudo touch /Applications/* ; killall Dock; killall Finder

원천

여러 줄 버전으로 다시 변경하는 방법을 알아보려고 합니다. 이것이 내가 지금 가지고 있는 것입니다:

sudo rm -rfv /Library/Caches/com.apple.iconservices.store
sudo find /private/var/folders/ -name com.apple.dock.iconcache -exec rm -rfv {} \;
sudo find /private/var/folders/ -name com.apple.iconservices -exec rm -rfv {} \;
sleep 3
sudo touch /Applications/*
killall Dock
killall Finder

나는 Ishmael의 버전에서 세미콜론이 줄 바꿈과 \;문자 그대로의 세미콜론에 사용된다는 것을 알고 있습니다. 하지만 두 개의 세미콜론 사이와 별표 뒤에 공백을 두는 것이 무슨 소용이 있을까요? 삭제해도 안전합니까?

 -exec rm -rfv {} \; ;
/Applications/* ;

답변1

쉘 언어 구문에서 공백을 언제 사용할지 여부는 사소한 문제가 아닙니다.

다양한 유형의 공간을 알아두는 것도 중요합니다.

  • 공백과 탭은 구문에서 토큰을 구분하는 데 사용됩니다.

  • 줄 바꿈은 토큰을 분리하지만 명령도 분리합니다. 예를 들어:

    array=(
      foo bar
      baz
    )
    

    (zsh의 구문은 이제 여러 다른 쉘에서 지원됩니다) 또는 ksh(C에서):

    (( 1
    + 2
    ))
    

    또는 POSIX sh(ksh에서도 올 수 있음):

    var=$((
      a + 
      b
    ))
    

    위의 공백, 탭 또는 줄 바꿈은 요소를 구분할 수 있습니다.

    하지만:

    cmd a
    cmd b
    

    두 개의 별도 명령을 실행하십시오.

    공백 대신 개행 문자를 사용할 수 있는 위치가 항상 명확한 것은 아니며 쉘마다 다를 수 있습니다.

  • 일부 쉘(bash 포함)에서는 일부 다른 문자가 다음과 같이 분류됩니다.공백로케일에서 구문의 토큰 구분 기호로 사용될 수 있으며 줄 바꿈하지 않는 공백이 있는 U+00A0과 같은 문자를 포함할 수 있습니다(다음으로 분류되는 로케일에서만).공백)의 경우 바이트로 인코딩됩니다 bash.

그런 다음 참조 연산자( "...", '...', $'...', $"...", \)가 있는데, 이는 쉘 구문에서 문자가 갖는 특별한 의미를 제거하는 데 사용할 수 있습니다.

또한 단독으로 사용하거나 다른 문자와 결합하여 문법에서 단어를 구분하는 표시를 형성할 수 있는 여러 특수 문자(대부분 ();<>&|어느 정도 `$)도 있으므로 주위에 공백을 추가할 필요가 없습니다.

예를 들어 ksh에서는 다음과 같이 작성할 수 있습니다.

[[(a == b||d>c)&&0<1 ]]&&(echo yes)|cat

바꾸다:

[[ ( a == b || d > c ) && 0 < 1 ]] && ( echo yes ) | cat

왜냐하면 ||, (, &&, <, &&...은 분리될 수 있는 단일 토큰이기 때문입니다.

Bash(최소 5.1)에서는 다음이 필요합니다.

[[(a == b||d>c)&&0 <1 ]]&&(echo yes)|cat

그렇지 않으면 일종의 오류가 발생한 것 같습니다.

$ bash -c '[[(a == b||d>c)&&0<1 ]]&&(echo yes)|cat'
bash: -c: line 1: unexpected token 284 in conditional command
bash: -c: line 1: syntax error near `&0<'
bash: -c: line 1: `[[(a == b||d>c)&&0<1 ]]&&(echo yes)|cat'

(아마도 Outside of [[...]], in cmd 0<file, 0<in 자체가 연산자이므로 별도의 토큰으로 처리될 가능성이 높기 때문일 것입니다.)

존재하다:

foo \;;bar

모호함은 없습니다. 단어 foo, 구분 기호로 처리되는 공백, 따옴표 ;( \;여기와 동일), 토큰 및 then 입니다. 따라서 다음과 같은 방식으로 처리됩니다.';'";";bar

foo ';' ; bar

공백을 추가해도 해가 되지 않으며 가독성을 높이는 데 도움이 됩니다.

이 코드는 다음과 같이 작성(및 개선)할 수도 있습니다.

sudo zsh -c '
  rm -rfv /Library/Caches/com.apple.iconservices.store
  find /private/var/folders/ \
    "("
       -name com.apple.dock.iconcache -o \
       -name com.apple.iconservices \
    ")" -prune -exec rm -rfv {} +
  sleep 3
  touch /Applications/*'
killall Dock
killall Finder

당신이 알아차릴 것:

  • sudo한 번만 실행하고 여러 줄로 묶인 인용 문자열을 별도의 zsh 호출에 대한 인수로 전달하면 모든 문자가 셸에 대한 특별한 의미를 잃습니다.
  • \개행 다음에 오는 것은 위에 언급되지 않은 또 다른 특별한 경우입니다. 이렇게 하면 개행 문자가 사라집니다(내부 셸의 경우, 외부 셸의 경우 백슬래시와 개행 문자는 작은따옴표 안에 있으므로 리터럴로 유지됩니다).
  • 우리는 한 명만 전화해요find
  • 우리는 실행될 명령을 구성하는 인수 목록을 분리 +하지 않기 위해( 셸이 아닌) 사용하므로 각 디렉터리에 대해 한 번이 아니라 제거할 모든 디렉터리에 대해 한 번 호출합니다.;find-execrm
  • -pruneso를 사용하면 삭제할 디렉토리 find에 들어가려고 시도하지 않습니다 .rm
  • 나는 더 명확하다고 생각하기 때문에 "("대신 사용하고 있습니다 . \(보통은 여기를 사용하는데 '(', 모든 것이 안에 있어서 '...'사용할 수 없습니다.
  • glob이 일치하지 않을 때 문자 그대로 전달되는 버그 기능이 있기 때문에 zsh -c대신 사용합니다 . 따라서 에 숨겨지지 않은 파일이 없으면 in이라는 이름의 파일이 생성됩니다 . zsh에서는 일치하는 항목이 없으면 오류가 발생합니다.sh -cshshtouch /Applications/**/Applications

관련 정보