mkdir, touch 등에 대한 bash/shell 경로 이름 확장?

mkdir, touch 등에 대한 bash/shell 경로 이름 확장?

따라서 대부분의 다른 쉘에서 유사한 작업을 수행하면 bash하위 디렉토리 내에 여러 하위 디렉토리나 파일이 생성되지 않습니다.

mkdir */test
touch */hello.txt

물론 이를 실제로 수행하는 방법은 여러 가지가 있습니다. 제가 선호하는 방법은 주로 가독성을 위해 가능한 경우 루프 find대신 사용하는 것입니다.for

하지만 내 질문은 위의 방법이 왜 작동하지 않는가입니다.
내가 이해한 바로는 전체 대상 파일/경로가 존재하지 않기 때문입니다. 그러나 시도하면 mkdir확실히 좋은 것입니다 touch. 나는 항상 전진했고 그것에 대해 정말로 의문을 품지 않았습니다.
하지만 내가 완전히 이해할 수 있도록 이에 대해 적절한 설명을 제공하는 사람이 있습니까?

답변1

특히 *nix를 사용하기 전에 다른 운영 체제를 사용해 본 경험이 있는 경우 많은 사람들이 문제를 겪고 있다는 사실을 간과할 수 있는 점은 다른 많은 운영 체제에서는 명령줄에 와일드카드를 전달하는 것이 일반적이라는 것입니다. 명령하다적절하다고 판단되는 대로 폐기하십시오. 예를 들어, Windows 명령 프롬프트에서 다음과 같습니다.

rename *.jpeg *.jpg

그러나 *nix에서는  mv프로그래머의 개별 명령(예: ) 작업을 단순화하기 위해 와일드카드(따옴표로 묶거나 이스케이프 처리하지 않은 경우)가 인터페이스 독립적인 방식으로 쉘에서 처리됩니다. 와일드카드는 명령 기능에 대한 인수로 사용됩니다. 파일 이름을 명령줄 인수로 사용하는 대부분의 프로그램은 이러한 파일이 존재할 것으로 예상합니다(예 , , , 및 어느 정도 , , 및 와 같은 규칙의 예외 mkdir이며 다른 파일도 있을 수 있음). 쉘이 와일드카드를 존재하지 않는 파일 이름으로 확장하는 것은 실제로 의미가 없습니다. 껍질의 경우(내 말은touchmkfifomknodcplnmvrename모든쉘 – Bourne, bash, csh, fish, ksh, zsh 등)은 다양한 방식으로 예외를 처리하기 어려울 수 있습니다.


즉, 원하는 결과를 얻는 방법에는 여러 가지가 있습니다. 와일드카드가 무엇으로 확장될지 알고 있고 길이가 길지 않은 경우 중괄호 확장을 사용하여 생성할 수 있습니다.

touch {red,orange,yellow,green,blue,indigo,violet}/rgb.txt

보다 일반적인 해결책:

sh -c 'for arg do mkdir -- "$arg"/test; done' -- *

자일스Bash에서 이 작업을 수행하는 다른 방법을 찾는 데 도움이 되었습니다.

benbradley=(*)
mkdir "${benbradley[@]/%//test}"

분명히 benbradley이것은 단지 식별자일 뿐입니다. 임의의 이름(예: 단일 문자)을 사용할 수 있습니다. 제대로 이해하기 위해 몇 번의 시도가 필요했기 때문에 분석해 보겠습니다.

  • identifier=valueidentifier (아직 존재하지 않는 경우)라는 이름의 (스칼라) 변수를 생성 하고 value값을 할당합니다. 예를 들어, G=Man. 예를 들어 ; 또는 더 안전하게 를 사용하여 스칼라 변수를 참조할 수 있습니다. 예를 들어, and는 정의되지 않았지만 is and is입니다.$identifier$G${identifier}$Gage$Gilla${G}ageManage${G}illaManilla
  • identifier=(value1 value2)identifier (아직 존재하지 않는 경우) 라는 배열 변수를 생성 하고 나열된 값을 할당합니다. 예를 들어,
      스펙트럼 = (빨간색, 주황색, 노란색, 녹색, 파란색, 남색, 보라색)
    또는
      all_text_files=(*.txt)
    $name첫 번째 요소를 참조하므로 오히려 쓸모가 없습니다. 예를 들어 is 및 is 와 같이 모든 요소를 ​​참조할 수 있습니다. 및 를 사용하여 전체 배열을 참조할 수 있습니다.${name[subscript]}${spectrum[0]}red${spectrum[4]}blue${name[@]}${name[*]}

그래서, 여기에 조각이 있습니다:

      "${벤브래들리[@]/%//테스트}"
  • ${parameter/pattern/string} 연장 및 교체된 가장 긴 일치 항목입니다.${parameter}patternstring
  • pattern로 시작 하는 경우 #확장된 값의 시작 부분에서 일치해야 합니다 parameter. pattern로 시작하는 경우 %확장된 값의 끝에서 일치해야 합니다 parameter. 다시 말해서,
      %(나머지 패턴)
    처럼 행동하다
      (나머지 정규식)$
    (예, 약간 거꾸로 된 것 같습니다). 따라서 a는 정규 표현식과 같습니다. pattern입력 문자열(검색 공간)의 끝과 일치합니다.%$
  • 나는 string를 사용하고 있습니다 /test. 따라서 이것은 매개변수의 끝을 다음으로 대체합니다 (즉, 매개변수에 /test 추가됨 )./test
  • 직관적이지 않은 또 다른 점은${parameter/pattern/string}언제나}다음으로 끝납니다. 필수는 아니며,할 수 없다, 세 번째 로 끝납니다 /. 그러므로 하나 /string구분 기호로 해석할 수 없으므로string/test 탈출할 필요 없이 /.
  • 또는 로 인덱스된 배열 변수인 경우 parameter대체 작업이 배열의 각 멤버에 차례로 적용됩니다.@*
  • 배열을 (대신)로 인용하고 결과를 큰따옴표로 묶으면 개별 요소를 하나의 긴 단어로 결합하지 않고도 배열 요소의 무결성(예: 공백 및 기타 특수 문자 유지)이 유지됩니다.${name[@]}${name[*]}

답변2

쉘은 명령을 호출하기 전에 와일드카드 패턴을 확장합니다. 바라보다G맨의 대답완전한 설명을 위해.

대부분의 셸에는 일치 항목에 텍스트 변환을 적용하기 위한 일종의 중간 명령이 필요합니다. Zsh는 즉시 일치 항목을 변경하는 방법을 제공합니다.글로벌 예선:

  • e또는 문자열(또는 배열을 수정하여 일치 항목 수 ) 을 수정하여 변경할 +수 있는 각 일치 항목에 대해 코드를 실행합니다.REPLYreply
  • :그 다음에역사 확장 수정자일부 기본 제공 변환 적용

예:

mkdir */(:s:/:/test:)     # takes advantage of the fact that each match ends with /, which it replaces by /test
mkdir *(/e:REPLY+=/test:)

답변3

쉘이 확장을 시도하기 때문에 작동하지 않습니다모두*/test아직 존재하지 않는 문자열입니다. 기본적으로 문자열은 자체적으로 확장됩니다. Bash를 사용한다면 다양한 내용을 확인하고 싶을 수도 있습니다.와일드카드 옵션원하는 방식으로 처리하세요.

관련 정보