sh
(Mac OSX 10.6) 에이 작은 스크립트가있어 파일 배열을 살펴 봅니다. 이 시점에서 Google의 도움이 중단되었습니다.
files="*.jpg"
for f in $files
do
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
echo $name
done
지금까지 (분명히 쉘 전문가들에게) 파일 이름이 제공된 문제와 일치 $name
하는지 여부에 따라 단순히 0, 1 또는 2를 보유 grep
합니다. 내가 원하는 것은 parens 안에있는 것을 캡처 ([a-z]+)
하여 변수에 저장하는 것 입니다.
가능한 경우에만 사용grep
하고 싶습니다 . 그렇지 않다면, Python이나 Perl 등을 피하십시오. sed
저는 쉘을 처음 접했고 * nix 순수 주의자 각도에서 이것을 공격하고 싶습니다.
또한, 매우 멋진 bonu 로서 쉘에서 문자열을 어떻게 연결할 수 있는지 궁금합니다. 내가 캡처 한 그룹이 $ name에 저장된 문자열 “somename” cat $name '.jpg'
입니까 , 끝에 “.jpg”문자열을 추가하고 싶 습니까?
시간이 있다면 무슨 일이 일어나고 있는지 설명하십시오.
답변
Bash를 사용하는 경우 grep
다음 을 사용할 필요조차 없습니다 .
files="*.jpg"
regex="[0-9]+_([a-z]+)_[0-9a-z]*"
for f in $files # unquoted in order to allow the glob to expand
do
if [[ $f =~ $regex ]]
then
name="${BASH_REMATCH[1]}"
echo "${name}.jpg" # concatenate strings
name="${name}.jpg" # same thing stored in a variable
else
echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
fi
done
정규식을 변수에 넣는 것이 좋습니다. 문자 그대로 포함 된 일부 패턴은 작동하지 않습니다.
이것은 =~
Bash의 정규식 일치 연산자를 사용합니다. 일치 결과는이라는 배열에 저장됩니다 $BASH_REMATCH
. 첫 번째 캡처 그룹은 인덱스 1에 저장되고 두 번째 (있는 경우) 인덱스 2에 저장됩니다. 인덱스 0은 전체 일치입니다.
앵커가 없으면이 정규 표현식 (및을 사용하는 정규 표현식 grep
)은 다음 예제 중 하나 이상과 일치하므로 원하는 것이 아닐 수도 있습니다.
123_abc_d4e5
xyz123_abc_d4e5
123_abc_d4e5.xyz
xyz123_abc_d4e5.xyz
두 번째와 네 번째 예를 제거하려면 정규식을 다음과 같이 만드십시오.
^[0-9]+_([a-z]+)_[0-9a-z]*
문자열은 하나 이상의 숫자로 시작 해야합니다 . 캐럿은 문자열의 시작을 나타냅니다. 정규식 끝에 달러 기호를 추가하면 다음과 같이됩니다.
^[0-9]+_([a-z]+)_[0-9a-z]*$
점이 정규식의 문자에 포함되지 않고 달러 기호가 문자열의 끝을 나타 내기 때문에 세 번째 예제도 제거됩니다. 네 번째 예제도이 일치에 실패합니다.
GNU를 가지고 있다면 grep
(약 2.5 이상이면 \K
연산자가 추가 된 것 같습니다.)
name=$(echo "$f" | grep -Po '(?i)[0-9]+_\K[a-z]+(?=_[0-9a-z]*)').jpg
\K
연산자 (가변 길이 모양 숨김)는 경기에 선행하는 패턴을 야기하지만, 결과에서 경기를 포함하지 않습니다. 고정 길이는 (?<=)
-괄호 앞에 패턴이 포함됩니다. 당신은 사용해야합니다 \K
한정사가 서로 다른 길이의 문자열을 일치 할 수있는 경우 (예를 들어 +
, *
, {2,4}
).
이 (?=)
연산자는 고정 길이 또는 가변 길이 패턴과 일치하며 “look-ahead”라고합니다. 또한 결과에 일치하는 문자열이 포함되지 않습니다.
대소 문자를 구분하지 않고 일치시키기 위해 (?i)
연산자가 사용됩니다. 그것은 패턴을 따라가므로 위치가 중요합니다.
파일 이름에 다른 문자가 있는지 여부에 따라 정규식을 조정해야 할 수도 있습니다. 이 경우 하위 문자열을 캡처하는 동시에 문자열을 연결하는 예를 보여줍니다.
답변
grep
적어도 일반적으로 순수하지는 않지만 실제로는 불가능합니다 .
그러나 패턴이 적합한 경우 grep
파이프 라인 내에서 여러 번 사용 하여 선을 알려진 형식으로 줄인 다음 원하는 비트 만 추출 할 수 있습니다. (이 도구 는이 도구를 좋아 cut
하고 sed
훨씬 나아집니다).
패턴이 조금 더 단순하다는 주장을 [0-9]+_([a-z]+)_
위해 다음과 같이 추출 할 수 있습니다.
echo $name | grep -Ei '[0-9]+_[a-z]+_' | grep -oEi '[a-z]+'
첫 번째 grep
는 전체 patern과 일치하지 않는 행을 제거하고 두 번째 grep
( --only-matching
지정한)는 이름의 알파 부분을 표시합니다. 패턴이 적합하기 때문에 작동합니다. “알파 부분”은 원하는 것을 끌어낼 수있을만큼 구체적입니다.
(제외 : 개인적으로 grep
+ cut
를 사용 하여 다음을 달성 할 것입니다 : echo $name | grep {pattern} | cut -d _ -f 2
. cut
구분 기호로 분할하여 행을 필드로 구문 분석하고 _
필드 2 만 반환합니다 (필드 번호는 1에서 시작합니다).
유닉스 철학은 한 가지 일을하고 잘 수행하는 도구를 가지고 사소하지 않은 작업을 수행하기 위해 도구를 결합하는 것이므로 grep
+ sed
등이 일을하는 더 Unixy 방법 이라고 주장합니다 🙂
답변
나는 이것에 대한 답변이 이미 받아 들여 졌음을 알고 있지만 “엄격히 * nix 순수 주의자 각도”에서 그것은 작업에 대한 올바른 도구 인 pcregrep
것처럼 보이지만 아직 언급되지 않은 것 같습니다. 줄을 바꾸어보십시오.
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
다음에
name=$(echo $f | pcregrep -o1 -Ei '[0-9]+_([a-z]+)_[0-9a-z]*')
캡처 그룹 1의 내용 만 가져옵니다.
이 pcregrep
도구는 이미 사용한 것과 동일한 구문을 모두 사용 grep
하지만 필요한 기능을 구현합니다.
이 매개 변수 는 베어 버전 인 경우 버전 -o
과 동일하게 작동 grep
하지만에서 pcregrep
표시 할 캡처 그룹을 나타내는 숫자 매개 변수도 허용합니다 .
이 솔루션을 사용하면 스크립트에서 최소한의 변경이 필요합니다. 하나의 모듈러 유틸리티를 다른 것으로 교체하고 매개 변수를 조정하면됩니다.
재미있는 참고 : 여러 개의 -o 인수를 사용하여 여러 캡처 그룹이 행에 나타나는 순서대로 반환 할 수 있습니다.
답변
내가 믿는 grep으로는 불가능
sed의 경우 :
name=`echo $f | sed -E 's/([0-9]+_([a-z]+)_[0-9a-z]*)|.*/\2/'`
그래도 보너스를 찌를 것입니다.
echo "$name.jpg"
답변
gawk를 사용하는 솔루션입니다. 자주 사용해야하는 기능이므로 만들었습니다.
function regex1 { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'1'}']}'; }
그냥 사용하기
$ echo 'hello world' | regex1 'hello\s(.*)'
world
답변
제안 사항-매개 변수 확장을 사용하여 마지막 밑줄에서 시작 부분과 마찬가지로 이름의 일부를 제거 할 수 있습니다.
f=001_abc_0za.jpg
work=${f%_*}
name=${work#*_}
그런 다음 name
값을 갖습니다 abc
.
Apple 개발자 문서를 참조 하고 ‘매개 변수 확장’을 검색 하십시오 .
답변
배쉬가 있다면 확장 글러브를 사용할 수 있습니다.
shopt -s extglob
shopt -s nullglob
shopt -s nocaseglob
for file in +([0-9])_+([a-z])_+([a-z0-9]).jpg
do
IFS="_"
set -- $file
echo "This is your captured output : $2"
done
또는
ls +([0-9])_+([a-z])_+([a-z0-9]).jpg | while read file
do
IFS="_"
set -- $file
echo "This is your captured output : $2"
done