역참조를 사용하더라도 여러 패턴에 대한 변수의 텍스트를 동시에 바꿀 수 있는 방법이 있습니까?
예를 들어, FILE=filename.ext
로 변경하고 싶지만 filename_sometext.ext
파일 확장자가 무엇인지 모르겠습니다 .ext
. 제가 아는 것은 확장자가 마지막 점 뒤에 있다는 것뿐입니다. 따라서 두 단계로 수행할 수 있습니다.
EXT=${FILE##*.}
FILE=${FILE%.*}_sometext.$EXT
한 단계로 완료할 수 있나요(예: ${FILE/.\(*\)/_sometext.\1}
[이것은 작동하지 않습니다])?
sed
그런데, / 등이 없는 awk
순수 쉘에서 이 작업을 수행 해야 합니다 . 내 쉘은 이지만 ksh
, bashisms로 이 작업을 수행할 수 있는 방법이 있다면 그것도 알고 싶습니다.
답변1
Bash 매개변수 확장표현 변수( FILE
예제에서는)는 매개변수 이름이어야 합니다. 그래서 그들은 둥지를 짓지 않습니다. 마지막 부분은 ${param/pattern/replacement}
문자열이어야 합니다. 따라서 역참조는 지원되지 않습니다.
내 유일한 제안은 다음을 사용하는 것입니다.
${EXT:+.$EXT}
파일에 확장자가 없을 때 뒤에 점을 추가하지 않으려면.
고쳐 쓰다
분명히 역 참조가 지원됩니다크쉬 93.
그래서 당신은 다음과 같은 것을 사용할 수 있습니다
FILE="${FILE/@(.*)/_something\1}"
답변2
FILE=${FILE%.*}_sometext.${FILE##*.}
이 특별한 경우에는 그것이 그 일을 할 것이라고 생각합니다 .
답변3
변하기 쉬운.
모든 셸에서 변수나 값을 연결할 수 있습니다.
$ a=One; b=Two; c=Three
$ d="$a$b$c"; echo $d
OneTwoThree
이 ${parameter%word}
구조POSIX입니다대부분의 쉘은 오랫동안 이 기능을 지원해 왔습니다.
가정적으로 FILE=filename.ext
다음과 같이 할 수 있습니다.
$ FILE="${FILE%.*}_sometext.${FILE##*.}"; echo "$FILE"
filename_sometext.ext
이것은 (요청한 대로) 한 줄이며 대부분의 쉘에서 작동합니다.
변수를 사용하는 것도 가능합니다(점이 여러 개인 경우에도).
#!/bin/bash
FILE=file.one.name.ext
ADDTEXT="_sometext"
EXT="${FILE##*.}"
echo "EXT=$EXT"
echo "final FILE=${FILE%.*}${ADDTEXT}.$EXT"
아니면 다음 한 줄만 사용하세요.
ONEFILE=${FILE%.*}${ADDTEXT}.${FILE##*.}
echo "one FILE=$ONEFILE"
패턴 교체
까다로운 부분은 ${parameter/pattern/string}
"패턴 대체"를 사용하려고 하는 것입니다.
변수는 많은 셸에서 작동합니다(비지박스 재도 포함).
NEWTEXT="${ADDTEXT}.${FILE##*.}"
echo "ash FILE=${FILE/.*/${NEWTEXT}}"
하지만 오래된 sh
Els에서는 그렇지 않습니다.
다음에서만 작동 FILE=filename.ext
:
bash(및 ksh, ksh93, mksh, zsh)에서는 작동하지만 ash, dash, sh 또는 csh에서는 작동하지 않습니다.
echo "bash FILE=${FILE/%.*/${ADDTEXT}.${FILE##*.}}"
%
인수 끝에서 일치 항목을 표시하기 위해 문자를 사용한다는 점에 유의하세요 (그러나 불행하게도 욕심이 많아 의 모든 포인트를 먹어치워 버립니다 FILE=file.one.name.ext
).
결론적으로
대체가 얼마나 탐욕스러운지를 제어하는 가장 좋은 방법은 별도의 변수를 사용하는 것입니다("패턴 대체"의 몇 가지 변수 대신).
답변4
FILE="${FILE%.*}_sometext${FILE#"${FILE%.*}"}"
쉘 변수에 $FILE
a가 포함되어 있으면 위 명령은 이전 .
값에서 마지막 값 이후의 .
모든 값을 뺀 값을 다시 할당합니다._sometext
그리고 마지막 이전 값 .
과 그 이후의 모든 값을 유지하세요.
그래서:
FILE=some.dot
FILE="${FILE%.*}_sometext${FILE#"${FILE%.*}"}"
printf %s\\n "$FILE"
some_sometext.dot
쉘 변수가 $FILE
다음과 같은 경우아니요점이 포함된 경우_sometext
문자열은 이전 값의 끝에만 추가됩니다.
FILE=no_dots_at_all
FILE="${FILE%.*}_sometext${FILE#"${FILE%.*}"}"
printf %s\\n "$FILE"
no_dots_at_all_sometext
이는 제가 한 것처럼 매개변수 확장을 중첩하지 않은 경우 발생할 수 있는 동작과의 중요한 차이점입니다.
FILE=no_dots_at_all
FILE="${FILE%.*}_sometext${FILE##*.}"
printf %s\\n "$FILE"
no_dots_at_all_sometextno_dots_at_all
매개변수 확장을 중첩하면 내부에서 외부로 평가되므로 가장 먼저 발생하는 일은 다음과 같습니다.
for FILE in some.dot no_dots_at_all
do printf %s\\n '${FILE#'"${FILE%.*}"'}'
done
${FILE#some}
${FILE#no_dots_at_all}
...쉘은 일치하는 모든 비트를 제거하고 나머지를 외부 확장에서 제거된 패턴으로 사용합니다. 그래서 있을 때아니요일치하는 비트 및 변수는 완전히 확장되고 외부 확장은 제거됩니다.모두변수 값을 표현식에 두 번 대체하는 대신 사용합니다.