길이를 알 수 없는 경로에서 파일 이름의 하위 문자열을 추출하고 싶습니다. 두 부분을 따로 할 수도 있는데, 임시 변수를 사용하지 않고 두 부분을 결합할 수 있는 방법이 있는지 궁금합니다.
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:2
basename
zsh
:t
첫 번째 숫자 순서꼬리:
num=${(MS)${a_path:t}##<->}
${var##pattern}
pattern
에서 일치하는 가장 긴 선행 문자열을 제거하는 ksh 연산자입니다$var
. 이M
플래그를 사용하면M
추가된 부분이 제거되는 대신 반환되고 시작 부분뿐만 아니라 ubstringS
도 검색됩니다 . 범위가 지정되지 않은 모든 숫자 시퀀스S
와 일치합니다.<->
<x-y>
_
다음에 나오는 숫자의 순서꼬리:num=${${a_path:t}/(#m)*_(<->)*/$match[1]}
(필수
extendedglob
;_digits
in이 없으면 완전한 tail을 반환합니다$a_path
.)또는:
[[ $a_path:t =~ '_([[:digit:]]+)' ]] && num=$match[1]