죄송합니다. 저는 쉘스크립팅을 처음 접했습니다. 명령과 관련된 옵션이 포함된 변수가 있습니다 find
.
TYPE=("-type f")
NAME=("-name \"*log*\"")
옵션이 포함된 변수를 관련 코드에 넣어 보았습니다.
- 이것은 작동합니다:
그리고 다음을 생성합니다(샘플 출력).LST_FILE=$(find ${2} ${TYPE} -mmin +${HOUR_TO_MIN})
viv/clean/prototype/asdadsadsa.log viv/clean/prototype/logo viv/clean/prototype/sadsadasdas.log.gz viv/clean/prototype/prototype/log viv/clean/prototype/prototype/fewfasfs viv/clean/prototype/prototype/og
- 그런데 추가하려고 하면
${NAME}
원하는 파일을 검색하기 위한 키워드 이름을 캡처할 수 없고 결과가 없습니다.
(결과 0개 생성)LST_FILE=$(find ${2} ${TYPE} ${NAME} -mmin +${HOUR_TO_MIN})
문제가 와일드카드, 특수 문자 또는 이와 유사한 것과 관련된 것 같습니다. 관련 사례에 대한 귀하의 제안에 진심으로 감사드립니다.
답변1
여기에는 두 가지 문제가 있습니다. 첫 번째 문제는 두 변수를 요소가 하나만 있는 배열로 정의한 다음 find
명령에서 간단한 스칼라 변수로 사용한다는 것입니다. 이렇게 하면 bash는 각 배열의 첫 번째 요소를 정중하게 반환합니다.
둘째, C.Aknesil이 지적했듯이 bash는 변수 확장 후 큰따옴표를 제거하지 않습니다. 사실, 그것은 실제로 문제가 되지 않습니다. 문제는 당신이 그것을 모르거나 bash가 왜 이런 식으로 동작하는지에 대한 것입니다 - "그것은 기능이지 버그가 아닙니다".
이 시도:
TYPE=(-type f)
NAME=(-name '*log*')
'*log*'
bash가 glob을 확장하지 않고 현재 디렉터리에서 일치하는 모든 파일을 배열에 추가하려면 여기에 따옴표가 필요합니다.
그런 다음 다음과 함께 사용해야 할 때 find
:
find "$2" "${TYPE[@]}" -mmin "+$HOUR_TO_MIN"
또는
find "$2" "${TYPE[@]}" "${NAME[@]}" -mmin "+$HOUR_TO_MIN"
그런데 여기서 $2
와 는 모두 $HOUR_TO_MIN
큰따옴표로 묶어야 하지만 {}
주변 문자와 구분할 필요가 없으므로 중괄호는 필요하지 않습니다. 예를 들어 $2
필수는 아니지만 {}
다음 ${2}3
과 같이 해석되므로 필수입니다 $23
.아니요예를 들어 "$2 다음에 3이 옵니다")는 그것들 없이 쉘에 의해 실행됩니다.
$HOUR_TO_MIN
인용하지 않아도 괜찮을 것입니다(아마도 스크립트에 정의되어 있고 공백 등과 같은 문제 문자가 없을 것이기 때문입니다). 그러나 인용해도 아무런 해가 없습니다.알다당신이 이런 일을 하고 싶지 않다는 것을 절대 확신하세요.왜)”는 개발할 가치가 있는 좋은 습관입니다.
$2
그러나 이는 사용자가 스크립트에 대한 인수로 제공하고 그 안에 무엇이든 포함할 수 있으며 항상 인용되어야 합니다.
참고: 파일 이름에는 공백, 탭, 줄 바꿈과 같은 공백부터 , 및 와 같은 쉘 메타 문자 LST_FILES=$(find ...)
에 이르기까지 모든 종류의 성가신 문자가 포함될 수 있으므로 이는 좋은 생각이 아닙니다 . 유일한 역할은;
&
>
|
할 수 없다파일 이름의 NUL. 이는 NUL이 신뢰할 수 있는 유일한 파일 이름 구분 기호임을 의미합니다.어느파일 이름.
대신 변수에서 find의 출력이 필요한 경우 배열을 사용하고 예를 들어 find
NUL을 출력으로 사용하도록 지시합니다 -print0
.
mapfile -d '' LST_FILES < <(find "$2" "${TYPE[@]}" "${NAME[@]}" -mmin "+$HOUR_TO_MIN" -print0)
이 mapfile
명령(라고도 함 readarray
)은 stdin에서 읽고 이를 사용하여 배열을 채웁니다. 이 예에서는 NUL을 구분 기호로 사용함을 나타냅니다 -d ''
.
다음을 시도해보고 그것이 어떻게 작동하는지 직접 확인하십시오.
$ mkdir junk
$ cd junk
$ touch foo bar baz 'file with spaces' $'file\nwith\nLFs'
$ ls
bar baz file?with?LFs file with spaces foo
$ mapfile -d '' LST_FILES < <(find . -type f -print0)
$ declare -p LST_FILES
declare -a LST_FILES=([0]="./foo" [1]=$'./file\nwith\nLFs' [2]="./baz"
[3]="./file with spaces" [4]="./bar")
$ echo "${#LST_FILES[@]}" # use ${#...} to count elements in an array
5
$ for f in "${LST_FILES[@]}"; do echo "$f" ; done
./foo
./file
with
LFs
./baz
./file with spaces
./bar
답변2
내 결론은 Bash가 토큰화 후에 개별 단어에 대한 인용문 제거를 수행하지 않는다는 것입니다. 따라서 제공한 패턴에는 "*log*"
큰따옴표가 포함되어 있습니다. 즉, 이름이 큰따옴표로 시작하고 끝나는 파일을 검색하는 것입니다.
~에서배쉬 매뉴얼:
확장 순서는 중괄호 확장, 인수 및 변수 확장, 산술 확장, 명령 대체(왼쪽에서 오른쪽으로 수행)입니다. [...] 이러한 확장을 수행한 후 원래 단어에 있는 따옴표 문자는 자체적으로 인용되지 않은 경우 제거됩니다(따옴표 제거).
다음 코드를 사용하여 이 동작을 관찰할 수 있습니다.
$ NAME=("-name \"*log*\"")
$ echo $NAME
-name "*log*"
보시다시피 $NAME
제공되는 방식 echo
은 제공되는 방식과 동일합니다 find
. echo
큰따옴표가 인쇄된다는 사실은 호출 전에 패턴 주위의 따옴표가 제거되지 않음을 보여줍니다 echo
.
수정 사항으로 변수 없이 패턴을 사용하는 것이 좋습니다 find
. 비슷한 코드 분해를 수행하려면 를 사용하는 함수를 만들고 find
나중에 해당 함수를 호출하면 됩니다.
function find_files {
find ... <pattern>
}
LST_FILE=$(find_files)
패턴을 변수에 저장할 수 있는 솔루션을 찾을 수 없습니다. 위의 솔루션으로 충분하길 바랍니다.