주어진 조건과 일치하는 디렉터리의 파일을 나열합니다. 디렉토리의 각 파일에 대해 수행하고 싶은 작업 중 하나는 6자리 날짜를 추출하여 변수에 넣는 것입니다. 내 스크립트는 현재 다음과 같습니다
for i in $(ls $INPUT_DIR | egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX); do
MYDATE=$("$i" | grep -oP '\d{6,6}')
echo $MYDATE
done
위의 결과는 오류입니다 "somefile": command not found
.
MYDATE=$("$i" | grep -oP '\d{6,6}')
나 에게 이상한 점은 echo "$i" | grep -oP '\d{6,6}'
.
"$i"
스크립트가 명령 대신 문자열로 전달되도록 하려면 어떻게 해야 합니까 ?
답변1
파일 이름에서 . 로 $INPUT_FILE_PREFIX
시작하고 끝나는 6자리 숫자를 구문 분석하려는 것 같습니다 $INPUT_FILE_SUFFIX
.
이렇게 하면 됩니다:
for name in "$INPUT_DIR/$INPUT_FILE_PREFIX"??????"$INPUT_FILE_SUFFIX"; do
test -f "$name" || continue
number=${name#$INPUT_DIR/$INPUT_FILE_PREFIX}
number=${number%$INPUT_FILE_SUFFIX}
printf "Number = %s\n" "$number"
done
숫자만 일치하는지 확인하려면(해당 문자가 무엇이든 단일 문자와 일치) 모든 것을 ?
로 변경하십시오.[0-9]
?
루프의 매개변수 대체는 값의 첫 번째 부분을 제거한 $name
다음 나머지 문자열의 마지막 부분을 제거하고 중간 숫자(접두사와 접미사 사이의 6개 문자)만 변수에 남겨 둡니다 $number
.
주문하다
MYDATE=$("$i" | grep -oP '\d{6,6}')
발견한 대로 $i
호출 명령에 포함된 모든 내용이 해석됩니다. 또한 당신은 그것을 echo
앞에 놓으면 "$i"
작동하게 될 것이라고 말했습니다. 그리고 그것은 그렇습니다:
MYDATE=$(echo "$i" | grep -oP '\d{6,6}')
귀하의 코드와 관련:왜 `ls`를 구문 분석하지 *않나요*?
답변2
bash를 사용하여 파일 이름을 반복하는 약간 다른 방법을 권장합니다.확장된 와일드카드파일 이름 수집:
shopt -s extglob
for d in "${INPUT_DIR}"/"${INPUT_FILE_PREFIX}"[0-9][0-9]@(0[1-9]|1[0-9])@(0[1-9]|[12][0-9]|3[01])"${INPUT_FILE_SUFFIX}"
do
[[ $d =~ ${INPUT_FILE_PREFIX}([[:digit:]]+)${INPUT_FILE_SUFFIX} ]]
MYDATE=${BASH_REMATCH[1]}
done
와일드카드 구문은 grep 문과 거의 동일합니다. 각 그룹은 @(...)
로 구분된 특정 패턴과 일치하는 요청을 소개합니다 |
. 내가 발견한 패턴(날짜 가정) [3]
은 단일 문자 클래스이므로 그 주위의 대괄호를 제거했습니다.
루프에 파일 이름이 있으면 for
조건식에 대해 bash의 정규식 연산자를 사용하여 =~
숫자를 MYDATE로 제거할 수 있습니다.
답변3
for i in $(ls $INPUT_DIR | egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX);
ls
일반적으로 이와 같은 구조에서는 사용할 이유가 없습니다 . 단지 명령을 읽기 어렵게 만들고 일부 코너 케이스 문제에 직면하게 될 뿐입니다(참조:BashGuide에서 구문 분석). 그러나 가지고 있는 정규식은 표준 쉘 glob으로 표현될 수 없으므로 이를 사용하는 것이 합리적입니다. 태그가 붙어 있기 때문에세게 때리다, 쉘에서 이를 수행하거나 다음을 사용할 수 있습니다.extglob
[[ .. ]]
(또는 정규식을 사용하여 더 넓은 glob-after 구성과 일치시킵니다.)
shopt -s extglob
for i in "$INPUT_DIR/$INPUT_FILE_PREFIX"[0-9][0-9]@(0[1-9]|1[0-2])@(0[1-9]|[12][0-9]|3[01])"$INPUT_FILE_SUFFIX" ; do
그렇게 엄격한 패턴이 정말로 필요하지 않다면 그냥 사용해도 됩니다 [0-9][0-9][0-9][0-9][0-9][0-9]
.
쌍 할당에서는 MYDATE
접두사와 접미사만 제거하려고 한다고 가정합니다. (접두사/접미사에 6자리 문자열이 포함된 경우 grep도 해당 문자열과 일치합니다.)
MYDATE=${i#"$INPUT_DIR/"} # remove the directory
MYDATE=${MYDATE#"$INPUT_FILE_PREFIX"} # remove the prefix
MYDATE=${MYDATE%"$INPUT_FILE_SUFFIX"} # and the suffix
전부:
shopt -s extglob
for i in "$INPUT_DIR/$INPUT_FILE_PREFIX"[0-9][0-9]@(0[1-9]|1[0-2])@(0[1-9]|[12][0-9]|3[01])"$INPUT_FILE_SUFFIX" ; do
MYDATE=${i#"$INPUT_DIR/"} # remove the directory
MYDATE=${MYDATE#"$INPUT_FILE_PREFIX"} # remove the prefix
MYDATE=${MYDATE%"$INPUT_FILE_SUFFIX"} # and the suffix
echo "$MYDATE"
done
답변4
시도해 봤어?Bash 프로세스 교체? 명령 방식이 더 쉬워지고 루프나 변수가 필요하지 않은 것 같습니다.
기본적으로 프로세스 대체는 잘 알려져 있지 않지만 매우 강력합니다.
프로세스 대체는 한 프로세스(또는 프로세스)의 출력을 다른 프로세스의 표준 입력으로 공급합니다.
따라서 명령을 다음과 같이 단순화할 수 있습니다.
grep -oP '\d{6,6}'<(egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX <(ls $INPUT_DIR))
그 뒤에 있는 논리는 더 간단한 버전으로 더 잘 이해할 수 있습니다.
user@yrmv-191108:~/nums$ ls .
1 10 2 3 4 5 6 7 8 9
user@yrmv-191108:~/nums$ grep 1 <(ls .)
1
10