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[@]}"
구성은 특별한 경우입니다. 각 문자열이 파일 이름 중 하나 인 문자열 목록으로 확장됩니다. 공백이나 기타 어려운 문자가 포함 된 파일 이름은 올바르게 처리됩니다.
댓글
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
는 다음에 언급 된 유형, & 다음에 언급 된 -type
는 d
= 디렉토리이므로 건너 뛸 것입니다. 디렉토리. 파일을 건너 뛰려면 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
(u
는 unset
/ disabled / off / 0
)
또는 shopt -s shoptName
( s
는 set
/ 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")
for f in "$DIR"/*.txt
= 미세for f in "$DIR/*.txt"
= 나누기