공백과 와일드 카드가있는 경로가있는 문자열의 Bash 스크립트 오류

Bash 스크립팅의 기본을 이해하는 데 문제가 있습니다. 지금까지 가지고있는 내용은 다음과 같습니다.

#!/bin/bash FILES="/home/john/my directory/*.txt" for f in "${FILES}" do echo "${f}" done 

모든 .txt 파일을 나열하기 만하면됩니다. for 루프에서 작업을 수행 할 수 있습니다.하지만 my directory의 공백과 가 제대로 재생되지 않습니다. 변수 이름에 중괄호를 사용하거나 사용하지 않고 큰 따옴표를 사용하거나 사용하지 않고 사용해 보았지만 여전히 모든 .txt 파일을 인쇄 할 수 없습니다.

이것은 아주 기본적인 것이지만, 피곤하고 똑바로 생각할 수 없기 때문에 여전히 어려움을 겪고 있습니다.

내가 뭘 잘못하고 있나요?

성공적으로 지원할 수있었습니다. 내 파일에 공백이나 별표가없는 경우 위의 스크립트 … 작업하려면 큰 따옴표와 중괄호를 사용하거나 사용하지 않고 실험해야했습니다. 하지만 공백과 별표가 모두있는 순간 모든 것이 엉망이됩니다.

답변

따옴표 안에 *는 파일 목록으로 확장되지 않습니다. 이러한 와일드 카드를 성공적으로 사용하려면 따옴표 밖에 있어야합니다.

와일드 카드가 확장 된 경우에도 표현식 "${FILES}"는 결과가 아닌 단일 문자열이됩니다. 파일 목록입니다.

효과적인 한 가지 접근 방식은 다음과 같습니다.

#!/bin/bash DIR="/home/john/my directory/" for f in "$DIR"/*.txt do echo "${f}" done 

위에서 파일 이름에 공백이나 기타 어려운 문자가 올바르게 처리됩니다.

보다 고급 접근 방식은 bash 배열을 사용할 수 있습니다.

#!/bin/bash FILES=("/home/john/my directory/"*.txt) for f in "${FILES[@]}" do echo "${f}" done 

이 경우 FILES는 파일 이름의 배열입니다. 정의를 둘러싼 괄호는 배열을 만듭니다. *는 따옴표 밖에 있습니다. "${FILES[@]}" 구성은 특별한 경우입니다. 각 문자열이 파일 이름 중 하나 인 문자열 목록으로 확장됩니다. 공백이나 기타 어려운 문자가 포함 된 파일 이름은 올바르게 처리됩니다.

댓글

  • 효과가 좋았습니다.
  • 그것 ‘ ‘ 함수를 통해 이와 같은 경로를 전달하는 경우 변수를 자체적으로 인용해야합니다. 더 큰 문자열의 일부로 연결하는 대신 : for f in "$DIR"/*.txt = 미세 for f in "$DIR/*.txt" = 나누기

Answer

John1024에 표시된대로 배열을 사용하는 것이 훨씬 더 합리적이지만 여기에서 split + glob 연산자를 사용할 수도 있습니다. 인용되지 않은 스칼라 변수).

해당 연산자의 glob 부분 만 원하므로 split 부분을 비활성화해야합니다.

#! /bin/sh - # that also works in any sh, so you don"t even need to have or use bash file_pattern="/home/john/my directory/*.txt" # all uppercase variables should be reserved for environment variables IFS="" # disable splitting for f in $file_pattern # here we"re not quoting the variable so # we"re invoking the split+glob operator. do printf "%s\n" "$f" # avoid the non-reliable, non-portable "echo" done 

답변

할 수있는 작업은 따옴표 밖에 와일드 카드 문자 만 남겨 두는 것입니다.
다음과 같이하십시오. . txt “
처리
완료
와일드 카드 자체가 공백으로 확장되면 ls -l을 사용하여 파일 목록을 생성하고 bash read를 사용하여 각 파일을 가져옵니다.

Answer

단일 행 기반 솔루션 (터미널에서 실행) :
/usr/bin/find "./" -not -type d -maxdepth 1 -iname "*.txt" -print0 | while IFS= read -r -d $"\0" f ; do { echo "${f}"; }; done; unset f;

귀하의 / OP “사례의 경우 "./"

스크립트 파일에서 사용하려면 :

 #!/bin/bash /usr/bin/find "./" -not -type d -maxdepth 1 -iname "*.txt" -print0 | while IFS= read -r -d $"\0" f ; do { echo "${f}"; # your other commands/codes, etc }; done; unset f;  

위의 기능은이 (권장) 방식으로도 달성 할 수 있습니다.

 #!/bin/bash while IFS= read -r -d $"\0" f ; do { echo "${f}"; # your other commands/codes, etc }; done < <(/usr/bin/find "./" -not -type d -maxdepth 1 -iname "*.txt" -print0); unset f;  

간단한 / 간단한 설명 :

"./" : 현재 디렉토리입니다. 디렉토리 경로를 지정합니다.
-not -type d : 여기서 -not는 다음에 언급 된 유형, & 다음에 언급 된 -typed = 디렉토리이므로 건너 뛸 것입니다. 디렉토리. 파일을 건너 뛰려면 d 대신 f를 사용하세요. 심볼릭 링크 파일을 건너 뛰려면 d 대신 l를 사용하세요.
-maxdepth 1 : 현재 (일명 : 하나) 디렉토리 수준에서만 파일을 찾도록 구성합니다. 각 & 첫 번째 하위 디렉터리 수준에서 파일을 찾으려면 maxdepth를 2로 설정합니다. -maxdepth를 사용하지 않으면 재귀 적으로 (하위 디렉터리 내부) 검색합니다.
-iname "*.jpg" : 여기서 -iname는 파일을 찾고 무시하도록 구성합니다 (위 / 아래). -파일 이름 / 확장자의 경우. -name는 대소 문자를 무시하지 않습니다. -lname는 심볼릭 링크를 찾습니다. 기타
-print0 : 현재 파일의 경로 이름을 표준 출력으로 인쇄 한 다음 ASCII NUL 문자 (문자 코드 0)를 인쇄합니다. 나중에 while에서 read를 사용하여 감지합니다.
IFS= : 여기서는 파일 이름이 공백으로 끝나는 경우에 사용됩니다. IFS와 함께 NUL / "" / \0를 사용하여 발견 된 각 파일 이름을 감지합니다. ” 찾기 “는 iv로 구분하도록 구성됩니다. -print0에서 제작 한 id = “0423c89122”>

.
read -r -d $"\0" fileName:$"\0"""/ NUL입니다. 파일 이름에 백 슬래시가있는 경우-r가 사용되었습니다.
읽기 [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name. ..] […]
-r 백 슬래시는 이스케이프 문자로 작동하지 않습니다. 백 슬래시는 줄의 일부로 간주됩니다. 특히 백 슬래시-개행 쌍은 줄 연속으로 사용할 수 없습니다.
done < <(...): 여기에서 전송 / 대체에 사용되는 프로세스-대체 ” find “의 출력을 ” 읽기 / ” while “-루프. 추가 정보 : https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html, https://wiki.bash-hackers.org/syntax/expansion/proc_subst, https://tldp.org/LDP/abs/html/abs-guide.html#PROCESS-SUB, https://tldp.org/LDP/abs/html/abs-guide.html#PSUBP


@ John1024의 다른 답변에서 그는 외부 유틸리티 인 “를 찾습니다.
” find “는 매우 효과적입니다. & 빠르기 때문에 처리 할 파일이 너무 많을 때 선호합니다.

@ John1024 “의 솔루션에서는 디렉터리에 파일이없는 경우 일치 규칙 줄을 사용하므로 [ ! -e "${f}" ]... 줄을 건너 뛰는 데 사용됩니다.
다음은 터미널에서 직접 사용할 단일 줄 솔루션입니다.
DIR="/home/john/my directory/" ; for f in "$DIR"*.txt ; do { [ ! -e "${f}" ] && continue; echo "${f}"; }; done; unset DIR;

다음은 스크립트입니다.

 #!/bin/bash DIR="/home/john/my directory/"; for f in "$DIR"*.txt ; do { [ ! -e "${f}" ] && continue; echo "${f}"; # your codes/commands, etc }; done; unset DIR;  

참고 : DIR의 디렉토리 끝에 "/" 슬래시 (디렉토리 표시기)가 있으면 일치 규칙에 , 다시 "/"를 사용할 필요가 없습니다.
또는 반대로 DIR에서 "/"를 사용하지 마십시오. 일치 규칙에서 사용합니다. "$DIR"/*.txt


[ ! -e "${f}" ]... 코드는 shell-option (일명 : ” shopt “) 사용 또는 사용 :
shopt -s nullglob

스크립트에 의해 쇼핑 상태가 변경된 경우 다른 bash 기반 스크립트 프로그램에서 예기치 않은 / 예상치 못한 문제가 발생합니다.

사용하는 모든 스크립트에서 일관된 동작을 유지하려면 bash, bash-shell-option “의 상태는 스크립트 내부에 기록 / 저장되어야하며, 스크립트에서 기본 기능 사용을 마치면 해당 셸 옵션을 이전 설정으로 다시 설정해야합니다.

백틱 (일명 : 억음 악센트, 일명 : 역 따옴표)을 사용합니다. `...` 명령 대체 (내부 bash 명령 코드 등), 새 하위 셸을 생성하지 않음, 더 넓은 지원 (일명 : 이식성) 등을 위해 백 슬래시의 문자 적 의미를 유지합니다. 백틱 기반 내부 bash-commands 등은 종종 스크립트와 같은 셸에서 실행할 수 있으므로 조금 더 빠릅니다. & 더 좋으며 여기서 처리하는 목적에도 더 좋습니다. $(...) 명령 대체를 선호하는 경우이를 사용하면 누구나 원하는 것을 선택하거나 피할 수있는 자유 & 권한이 있습니다. 추가 정보 : 여기 .

따라서 위의 스크립트가 다시 표시됩니다. 이번에는 쇼핑의 이전 설정이 복원 된 & 스크립트를 종료하기 전에 :

 #!/bin/bash DIR="/home/john/my directory/"; ub="/usr/bin"; # shopt = shell-option(s). # Setting-up "previous-nullglob" state to "enabled"/"on"/"1": p_nullglob=1; # The "shopt -s" command output shows list of enabled shopt list, so if # nullglob is NOT set to ON/enabled, then setting "previous_nullglob" as 0 [ "`shopt -s | ${ub}/grep nullglob`" == "" ] && p_nullglob=0; # Enabling shell-options "nullglob": shopt -s nullglob; # previous code, but without the extra checking [ ! -e "${f}" ]... line: for f in "$DIR"*.txt ; do { echo "${f}"; # your codes/commands, etc }; done; # As we have utilized enabled nullglob shopt, its now in enabled state, # so if previously it was disabled only-then we will disable it: [ "$p_nullglob" -eq "0" ] && shopt -u nullglob; unset DIR; unset p_nullglob ub;  

shopt -p shoptName의 출력 (예 : shopt -p dotglob)는
둘 중 하나 일 수 있습니다. shopt -u shoptName (uunset / disabled / off / 0)
또는 shopt -s shoptName ( sset / enabled / on / 1)입니다.
위치 "s" 또는 "u"의 문자는 항상 7에 있습니다 (왜냐하면 bash에서는 string “의 문자 위치는 0에서 시작합니다. 즉, 문자열의 첫 번째 문자가 0 위치에 있습니다.
"u" 또는 변수에 저장하여 이전 상태를 복원하는 데 사용할 수 있습니다.
그리고이 방법 (위에서 언급 한)을 적용하여 쇼핑 상태를 저장 / 복원하면 외부 도구 "grep"를 사용하지 마십시오.

"." 파일을 보려면 즉, 숨겨진 "txt" 파일을 보려면 "dotglob" 쇼핑을 활성화해야합니다.

따라서 이번에는 "dotglob"에 &가 포함되어 HIDDEN "txt" 파일을 표시 할 수 있습니다.

 #!/bin/bash DIR="/home/john/my directory/"; p_nullglob="u"; pSS="`shopt -p nullglob`"; [ "${pSS:7:1}" == "s" ] && p_nullglob="s"; p_dotglob="u"; pSS="`shopt -p dotglob`"; [ "${pSS:7:1}" == "s" ] && p_dotglob="s"; shopt -s nullglob dotglob; for f in "$DIR"*.txt ; do { echo "${f}"; # your codes/commands, etc }; done; [ "$p_nullglob" == "u" ] && shopt -u nullglob; [ "$p_dotglob" == "u" ] && shopt -u dotglob; unset DIR; unset p_nullglob p_dotglob pSS;  

쇼핑을 저장 / 복원하는 더 간단한 방법이 있습니다. 옵션 / 값.
Isaac 여기 에 환경 저장 + 복원 방법을 게시했습니다. / Shopt 변수 / 옵션 상태 / 값.

” nullglob “의 쇼핑 상태 저장 :

... # your primary-function codes/commands, etc lines
” nullglob의 이전 쇼핑 상태 복원 “, 스크립트를 종료하기 전 :
eval "$p_nullglob" ;

여러 쇼핑 상태를 다음과 같이 저장할 수 있습니다.
p_multipleShopt="`shopt -p nullglob dotglob`";
복원 프로세스는 이전과 동일합니다.
eval "$p_multipleShopt" ;

모든 쇼핑 상태를 다음과 같이 저장합니다.
p_allShopt="`shopt -p`";
복원 프로세스는 이전과 동일합니다.
eval "$p_allShopt" ;

다음은 또 다른 bash 기반 솔루션입니다.

 #!/bin/bash DIR="/home/john/my directory/"; p_allShopt="`shopt -p`"; shopt -s nullglob dotglob; for f in "$DIR"*.txt ; do { echo "${f}"; # your codes/commands, etc }; done; eval "$p_allShopt" ; unset DIR p_allShopt;  

eval 사용은 위의 경우 안전합니다. "$p_allShopt" 변수는 사용자가 제공 한 데이터 나 그렇지 않은 데이터를 보유하지 않기 때문입니다. 삭제, 해당 var는 bash 내부 명령 shopt의 출력을 보유하고 있습니다.
여전히 eval를 피하려면 아래를 사용하십시오. lution :

 #!/bin/bash DIR="/home/john/my directory/"; p_allShopt="`shopt -p`"; shopt -s nullglob dotglob; for f in "$DIR"*.txt ; do { echo "${f}"; # your codes/commands, etc }; done; while IFS= read -a oneLine ; do { ${oneLine} ; }; done < <(echo "$p_allShopt") ; unset DIR p_allShopt oneLine;  

몇 안되는 (기타) 주목할만한 & 관련 SHOPT 는 다음과 같습니다.

  • nocaseglob : 설정하면 Bash는 파일 이름 확장을 수행 할 때 대소 문자를 구분하지 않습니다.
  • nocasematch : 설정하면 case 또는

    조건부 명령, 패턴 대체 단어 확장을 수행 할 때 또는 프로그래밍 가능한 완성의 일부로 가능한 완성을 필터링 할 때.

  • dotglob : 설정된 경우 Bash는 ‘.’에 파일 이름 확장 결과가 표시됩니다. 파일 이름 ‘.’‘..’는 dotglob이 설정되어 있어도 항상 명시 적으로 일치해야합니다.
  • nullglob : 설정된 경우 , Bash는 파일과 일치하지 않는 파일 이름 패턴이 자체가 아닌 null 문자열로 확장되도록 허용합니다.
  • extglob : 설정된 경우 위에서 설명한 확장 패턴 일치 기능 ( 패턴 일치 )가 활성화됩니다.
  • globstar : 설정하면 파일 이름 확장 컨텍스트에 사용되는 패턴 ‘**’가 모든 파일과 일치하며 0 개 이상의 디렉터리 및 하위 디렉터리. 패턴 뒤에 ‘/’가 오면 디렉토리와 하위 디렉토리 만 일치합니다.

답변

파일 집합을 처리하려는 경우 이름에 공백이 있거나 다른 scape 코드가있을 수 있으므로 시작하기 전에 for loop 또는 find command IFS bash env variable를 다음으로 설정합니다.

IFS=$(echo -en "\n\b") 

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다