
길이를 알 수 없는 경로에서 파일 이름의 하위 문자열을 추출하고 싶습니다. 이 두 부분을 따로 할 수도 있는데, 임시 변수 없이 두 부분을 합칠 수 있는 방법이 있는지 궁금합니다.
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}
또한 매개변수 확장을 사용하는 것이 basename을 호출하는 것보다 빠릅니다.
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
from 과 일치하는 가장 긴 선행 문자열을 제거하는 ksh 연산자입니다$var
.M
플래그를 사용하면M
연결된 부분이 제거되는 대신 반환되고 시작 부분뿐만 아니라 ubstring도S
찾습니다 .S
그리고<->
임의의 일련의 숫자(<x-y>
경계가 지정되지 않음)와 일치합니다._
a 뒤 의 일련의 숫자꼬리:num=${${a_path:t}/(#m)*_(<->)*/$match[1]}
(필요합니다 . 에
extendedglob
없으면 전체 꼬리를 반환합니다 .)_digits
$a_path
또는:
[[ $a_path:t =~ '_([[:digit:]]+)' ]] && num=$match[1]