한 변수에 대한 grep 명령의 결과를 다른 변수로 가져오는 방법

한 변수에 대한 grep 명령의 결과를 다른 변수로 가져오는 방법

주어진 조건과 일치하는 디렉터리의 파일을 나열합니다. 디렉토리의 각 파일에 대해 수행하고 싶은 작업 중 하나는 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

관련 정보