표준 유닉스 유틸리티는 "foo.bar.baz"를 "foo.bar" + ".baz"로 분할합니까?

표준 유닉스 유틸리티는 "foo.bar.baz"를 "foo.bar" + ".baz"로 분할합니까?

다음과 같이 $basename두 부분의 출력 $stem합계가 포함된 문자열을 분할하고 싶습니다 .$ext

  1. 이 문자열은 "${stem}${ext}"원래 문자열과 동일합니다 $basename.
  2. 또는 비어 있을 $stem$ext있습니다( 의 문자열에 따라 다름 $basename).
  3. 비어 있지 않으면 $ext다음으로 시작하고 .더 이상 포함할 수 없습니다..

이를 위해 쉘 함수를 작성하는 것은 어렵지 않습니다. 그러나 그렇게 하기 전에 이를 수행할 수 있는 표준 Unix 명령이 있는지 알고 싶습니다.

편집하다:

FWIW, () 스크립트에서 내가 코딩한 방식은 zsh다음과 같습니다.

stem=${basename%.*}
ext=${basename#"$stem"}

편집: 오타( ${base#...-> ${basename#...)를 수정하고 Stephane Chazelas의 제안( ...#$stem-> ...#"$stem")을 통합했습니다.

답변1

Bash에 포함된 일반적인 문자열 구문 분석 기능을 사용하여 원하는 것에 매우 근접하게 작업을 수행할 수 있습니다.

$ F="foo.bar.baz"

$ echo ${F%.*}
foo.bar

$ echo ${F/*./.}
.baz

따라서 다음과 같이 정리할 수 있습니다.

$ $ F="foo.bar.baz"

$ stem=${F%.*}
$ ext=${F/*./.}

echo "${stem}${ext}"
foo.bar.baz

Bash 매뉴얼 페이지에서

${F%.*}
${parameter%word}
${parameter%%word}
   Remove  matching suffix pattern.  The word is expanded to produce a pattern 
   just as in pathname expansion.  If the pattern matches a trailing portion
   of the expanded value of parameter, then the result of  the  expansion  is
   the expanded  value  of  parameter with the shortest matching pattern (the
   ``%'' case) or the longest matching pattern (the ``%%'' case) deleted.  If
   parameter is @ or *, the pattern removal operation is applied  to  each
   positional parameter  in turn, and the expansion is the resultant list.  
   If parameter is an array variable subscripted with @ or *, the pattern
   removal operation is applied to each member of the array in  turn,  and  
   the  expansion  is  the resultant list.
${/*./.}
${parameter/pattern/string}
   Pattern  substitution.   The pattern is expanded to produce a pattern just
   as in pathname expansion.  Parameter is expanded and the longest match of 
   pattern against its value is replaced with string.  If pattern  begins 
   with  /, all  matches  of  pattern are replaced with string.  Normally
   only the first match is replaced.  If pattern begins with #, it must match
   at the beginning of the expanded value of parameter.  If pattern  begins
   with  %,  it  must match  at the end of the expanded value of parameter.
   If string is null, matches of pattern are deleted and the / following
   pattern may be omitted.  If parameter is @ or *, the substitution operation
   is  applied  to  each  positional  parameter in turn, and the expansion 
   is the resultant list.  If parameter is an array variable subscripted
   with @ or *, the substitution operation is applied to each member of the
   array in turn, and the expansion  is  the resultant list.

이러한 기능에 대한 내용은 다음에서 읽을 수 있습니다.배쉬 매뉴얼 페이지.

답변2

쉘 변수를 설정하는 명령은 있을 수 없습니다. 왜냐하면 변수는 쉘 프로세스 내부에 있는 것이므로 자체 프로세스에 있는 다른 명령이 이를 변경할 수 없기 때문입니다.

셸을 사용하면 다음을 수행할 수 있습니다.

var=$(some-command)

명령의 출력을 검색합니다(후행 개행 없이). 그러나 명령의 두 결과가 모두 필요한 경우에는 더 까다로워집니다.

이를 수행하는 한 가지 방법은 다음과 같습니다.

eval "$(some-command)"

그중 some-command는 다음 내용을 출력합니다.

var1='something' var2='someotherthing'

그러나 물어보기 전에 경로를 가져와서 이를 디렉터리, 기본 이름 및 확장명(그게 무엇을 의미하든)으로 분할하는 표준 명령은 없습니다.

이제 셸 자체에는 이 목적을 위한 내부 기능이 있을 수 있습니다. 예 csh를 들어 zsh머리, 꼬리, 확장을 제공하는 수정자가 있습니다. 그림 zsh:

file=/path/to/foo.bar/
head=$file:h
tail=$file:t
ext=$file:e
rest=$file:r

...이제 or , /또는 .bashrc과 같은 파일에 대해 이것이 무엇이어야 하는지 생각해 보고 싶을 수도 있습니다 foo.tar.gz.

이제 표준 POSIX 구문을 찾고 있다면 이미 (거의) 그것을 가지고 있습니다: rest=${file%.*}. 구체적 ${file#$rest}으로 말하세요 zsh. POSIX 구문에서는 가 필요하며 ext=${file#"$rest"}, 그렇지 않으면 $rest패턴으로 처리됩니다. 문자 (예 : ) $file가 포함된 경로를 포함 하면 원하는 대로 작동하지 않을 수 있습니다./foo.d/bar

답변3

문자열에 개행 문자가 포함되어 있지 않은 경우:

start cmd:> echo foo.bar.baz | sed 's/\(^.*\)\(\.[^\.]*$\)/\1/'
foo.bar

start cmd:> echo foo.bar.baz | sed 's/\(^.*\)\(\.[^\.]*$\)/\2/'
.baz

답변4

"foo.bar"라고 합시다. ext가 누락되고 항상 2~3개의 마침표가 있는 경우 유효한 출력입니다.:

basename='foo.bar.baz'
stem=$(echo $basename | awk '{ split($1,a,"."); print a[1] "." a[2]; }')
ext=$(echo $basename | awk '{ split($1,a,"."); print "." a[3]; }');
echo $stem$ext

관련 정보