Bash 문자열 슬라이싱에서 표현식 출력 사용

Bash 문자열 슬라이싱에서 표현식 출력 사용

길이를 알 수 없는 경로에서 파일 이름의 하위 문자열을 추출하고 싶습니다. 두 부분을 따로 할 수도 있는데, 임시 변수를 사용하지 않고 두 부분을 결합할 수 있는 방법이 있는지 궁금합니다.

INPUT_PATH=/path/to/subfolder/file_17.txt 
# I would like to extract "17", the filname will always be 'file_XX.txt'
# The subfolder name is variable length 

TMP=$(basename ${INPUT_PATH})
FILE_NUMBER=${TMP:5:2}
echo ${FILE_NUMBER} # This works as expected

시도해 보았 ${$(basename $INPUT_PATH):5:2}으나 이로 인해 심각한 대체 오류가 발생했습니다. 이를 수행하기 위한 팁이 있습니까?

답변1

문제에 대해 다른 접근 방식을 취하고 기능만 사용하여 한 줄 솔루션을 제공하십시오 bash.

$ cat demo.sh
#!/bin/bash

INPUT_PATH=/path/to/subfolder/file_17.txt

FILE_NUMBER=${INPUT_PATH:((${#INPUT_PATH} -6)):2}
echo ${FILE_NUMBER}
$

$./demo.sh
17

더 간단한 방법은 문자열의 끝에서부터 카운트다운하는 것입니다.

FILE_NUMBER=${INPUT_PATH: -6:2}

분명히 해결책은 "##XXXX"로 끝나는 문자열 변수에 따라 달라집니다. 여기서 "##"은 관심 있는 두 자리이고 "XXXX"는 문자열의 마지막 4자입니다.

답변2

bash를 사용하고 있으므로 정규식 일치를 사용할 수 있습니다.

if [[ $input =~ ([[:digit:]]+)\.txt$ ]]; then
    file_num=${BASH_REMATCH[1]}
fi

답변3

가장 쉬운 방법은 TMP 대신 FILE_NUMBER를 사용하는 것입니다.

FILE_NUMBER=$(basename ${INPUT_PATH})
FILE_NUMBER=${FILE_NUMBER:5:2}

또한 매개변수 확장을 사용하는 것이 기본 이름을 호출하는 것보다 빠릅니다.

FILE_NUMBER=${INPUT_PATH##*/}
FILE_NUMBER=${FILE_NUMBER:5:2}

sed를 사용하면 한 줄로 모든 작업을 수행할 수 있지만 속도가 느리고 가독성이 떨어집니다.

FILE_NUMBER=$(sed 's|.*/||;s/.....\(..\).*/\1/' <<<"$INPUT_PATH")

답변4

zsh대신 사용하는 사람들의 경우 bash:

  • 문자 6~7꼬리basename다음에 의해 반환된 경로 부분:

    num=${${a_path:t}[6,7]}
    

    ( $var:t에서 메일을 csh받다 t)

    호환성을 위해 최근에 추가된 이 연산자를 사용할 수도 있습니다 num=${"$(basename -- "$a_path")":5:2}. 명령 대체는 배열을 생성하지 않도록 따옴표로 묶어야 하며, 따라서 배열 항목의 시퀀스가 ​​아닌 문자 시퀀스를 선택합니다. 그러나 명령 대체 및 실행을 사용하는 것은 기본 제공 연산자를 사용하는 것보다 궁극적으로 효율성과 안정성이 떨어집니다.ksh93 ${var:offset:length}zsh:5:2basenamezsh:t

  • 첫 번째 숫자 순서꼬리:

    num=${(MS)${a_path:t}##<->}
    

    ${var##pattern}pattern에서 일치하는 가장 긴 선행 문자열을 제거하는 ksh 연산자입니다 $var. 이 M플래그를 사용하면 M추가된 부분이 제거되는 대신 반환되고 시작 부분뿐만 아니라 ubstring S도 검색됩니다 . 범위가 지정되지 않은 모든 숫자 시퀀스 S와 일치합니다.<-><x-y>

  • _다음에 나오는 숫자의 순서꼬리:

    num=${${a_path:t}/(#m)*_(<->)*/$match[1]}
    

    (필수 extendedglob; _digitsin이 없으면 완전한 tail을 반환합니다 $a_path.)

    또는:

    [[ $a_path:t =~ '_([[:digit:]]+)' ]] && num=$match[1]
    

관련 정보