변수의 순수 쉘 복합 대체

변수의 순수 쉘 복합 대체

역참조를 사용하더라도 여러 패턴에 대한 변수의 텍스트를 동시에 바꿀 수 있는 방법이 있습니까?

예를 들어, 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}}"

하지만 오래된 shEls에서는 그렇지 않습니다.


다음에서만 작동 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%.*}"}"

쉘 변수에 $FILEa가 포함되어 있으면 위 명령은 이전 .값에서 마지막 값 이후의 .모든 값을 뺀 값을 다시 할당합니다._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}

...쉘은 일치하는 모든 비트를 제거하고 나머지를 외부 확장에서 제거된 패턴으로 사용합니다. 그래서 있을 때아니요일치하는 비트 및 변수는 완전히 확장되고 외부 확장은 제거됩니다.모두변수 값을 표현식에 두 번 대체하는 대신 사용합니다.

관련 정보