저는 다양한 사람들이 수동으로 만든 이러한 파일을 가지고 있습니다. 형식은 특정 규칙을 따르지만 균일하지는 않습니다.
다음 세 줄을 생각해 보세요.
"erroneous_data_F08R16_recordeded_by_tech21"
"erroneous_data_F8R16_recordeded_by_tech021"
"erroneous_data_F008R016_recordeded_by_tech21"
모두 같은 것을 가리킵니다. F008 또는 F08 또는 F8은 파일 번호 8을 의미합니다. R16 또는 R016 또는 (가능한 경우 R[단위 수])는 줄 번호 16을 의미합니다.
주어진 파일에 이러한 라인이 있으면 while read line
루프를 사용하여 스캔합니다.
내가 원하는 것은 위의 세 줄 예제에 대한 F008R016과 같이 파일과 줄 번호 부분을 균일하게 만드는 것입니다. 왜냐하면 내 파일 번호는 3자리를 초과하지 않고(999에 도달한 후 롤링되며 줄 번호는 절대 그렇지 않음) 여러 개가 있기 때문입니다. 하지만 일관성을 위해 3자리 숫자라고 가정해 보겠습니다. 처리해야 하는 이 파일에는 구조화되지 않은 주석도 있으므로 첫 번째 작업은 줄을 감지하여 여러 줄로 나누는 것입니다. 다른 임시 파일을 만든 다음 통합하세요.
이를 달성하기 위해 내 계획은 패턴과 일치하는 정규식에 대한 줄과 grep을 에코하는 것입니다. 불행하게도 정규식은 나에게 적합하지 않습니다.
지금까지 행의 file#row# 구조를 감지하는 데 갇혀 있었습니다.
cat InputFile | while read line
do
echo $line | grep '[F,f]\d\d[R,r]\d\d' >/dev/null #this is assuming two digit file number and 2 digit row number
result=$?
if [ $result -eq 0 ]
then
echo $line >tempfile
fi
done
줄에 F08R16 패턴이 포함되어 있어도 grep 명령의 이 정규식 일치는 항상 실패합니다.
이 작업이 완료되면 이 하위 문자열을 변수로 추출하고 변수의 구조를 분석하고 필요한 경우 앞에 0을 추가하여 균일하게 만듭니다.
내 정규식을 수정하고 변수 추출이라는 더 높은 목표를 달성하기 위한 제안이 있으면 크게 감사하겠습니다.
어쨌든 저는 CentOS 버전 6.7을 개발 중이었지만 사용 가능한 다른 배포판이 있었습니다.
답변1
f
a가 나올 때까지 또는 an F
, 그 다음 1, 2 또는 3개의 숫자, 그 다음 or r
, R
그 다음 1, 2 또는 3개의 숫자를 다시 일치시키길 원한다고 가정합니다 _
. 그렇다면 다음을 수행할 수 있습니다(GNU 사용 grep
).
grep -iP 'f\d{1,3}r\d{1,3}_' InputFile > tmpfile
또는 GNU가 아닌 경우 grep
:
grep -iE 'f[0-9]{1,3}r[0-9]{1,3}_' InputFile > tmpfile
그러나 이것은 거의 확실합니다.XY 문제. 실제로 쉘에서는 이런 종류의 작업을 수행하고 싶지 않습니다. 예를 들어 다음 perl
줄은 모든 관련 줄의 형식을 올바르게 지정합니다.
$ perl -pe 's/_f(\d+)r(\d+)_/sprintf("_F%03dR%03d_",$1,$2)/ei' file
"erroneous_data_F008R016_recordeded_by_tech21"
"erroneous_data_F008R016_recordeded_by_tech021"
"erroneous_data_F008R016_recordeded_by_tech21"
이는 그러한 문제를 피하기 위해 어떤 트릭을 사용할 수 있는지에 대한 아이디어를 제공하기 위한 것입니다.
답변2
어서 - 그거 미친 짓이야 echo
.grep
<infile grep -iE '([fr][0-9]+){2}' >outfile
...당신이 요청한 라인을 얻을 것입니다. 호출은 cat
파이프를 통해 파일을 셸에 쓴 다음 read
다양한 셸 구문 문자를 바이트 단위로 해석하고 제거한 다음 바이트 단위로 다른 파이프에 복사하므로 echo
조용히 성공할 수 있습니다 grep
.
grep
일치하는 결과만 귀하에게 기록됩니다. 행 수 등을 일치시키려면 를 사용하고, -c
행의 행 번호를 일치시키려면 을 사용하십시오 -n
. 대소문자를 구분하지 않으려면 을 사용 -i
하십시오.man grep
실시간으로 스트림을 편집하려면 다음을 사용할 수 있습니다 sed
.
sed -Ee:t -e's/((_)[Ff]|[0-9]{3,}[Rr])([0-9]{1,2}(\2|[Rr]))/\10\3/g;tt'
sed
작동하려면 GNU/BSD/AST가 필요합니다 . 그러나 그것은 매우 잘 작동합니다:
sed -Ee:t -e's/((_)[Ff]|[0-9]{3,}[Rr])([0-9]{1,2}(\2|[Rr]))/\10\3/g;tt' \
<<""
"erroneous_data_F08R16_recordeded_by_tech21"
"erroneous_data_F8R16_recordeded_by_tech021"
"erroneous_data_F008R016_recordeded_by_tech21"
"erroneous_data_F008R016_recordeded_by_tech21"
"erroneous_data_F008R016_recordeded_by_tech021"
"erroneous_data_F008R016_recordeded_by_tech21"
여기에 와서 기술 21에 대해 불평하는 사람은 당신이 처음이 아닙니다. 누군가 그 사람을 바로잡아야 합니다.
답변3
terdon의 perl
답변은 확실히 우아하며 동의합니다. 모든 데이터에 대해 균일하고 일관된 형식을 갖는 것이 목표라면 변경해야 하는 행을 개별적으로 분리할 필요가 없습니다. 마음에 들지 않는 경우 perl
(또는 없는 경우) sed
해결 방법은 다음과 같습니다.
sed -re 's/_[Ff]([0-9]+)[Rr]([0-9]+)_/_F00\1R00\2_/' \
-e 's/_F0*([0-9]{3})R0*([0-9]{3})_/_F\1R\2_/'
한 줄로 입력할 수 있습니다( \
첫 번째 줄의 끝 부분 생략). 나는 이것이 그렇게 perl
우아한 해결책이 아니라는 것을 인정한다 . 이는 두 단계로 진행됩니다.
- 패턴에서 각 또는 (또는 또는 )
00
뒤에 추가합니다 . 그러면 한 자리는 로, 두 자리는 로, 세 자리는 으로 변경됩니다. (첫 번째 단계도 대문자 또는입니다.)F
R
f
r
_ F file_number R file_number _
8
008
08
0008
008
00008
f
r
- 패턴에서 각각 또는 뒤에
F
마지막 세 자리 숫자 앞에 나타나는 0을 원하는 만큼 제거합니다. so는 유지되고 while 및 는 로 변경됩니다.R
_ F file_number R file_number _
008
0008
00008
008
귀하의 버전이 (확장 정규식 사용) 옵션을 sed
지원하지 않는 경우 다음을 사용하십시오.-r
sed -e 's/_[Ff]\([0-9]*\)[Rr]\([0-9]*\)_/_F00\1R00\2_/' \
-e 's/_F0*\([0-9]{3}\)R0*\([0-9]{3}\)_/_F\1R\2_/'
\(…\)
대신 (…)
및 *
대신 사용 하십시오 +
. ( 같은 의미는 아니지만 이 경우에는 또는 같은 문자열이 있는 행이 없으면 충분히 가깝습니다 *
. 실제로 첫 번째 명령에서도 대신 사용할 수 있습니다 .)+
_FR42_
_F17R_
*
+
사용 방법
sed option(s) scripts InputFile
또는 입력 파일을 처리하고 화면에서 결과를 봅니다.
sed option(s) scripts < InputFile
sed option(s) scripts InputFile > output_file
또는 입력 파일을 처리하고 결과를 새 파일로 보냅니다.
sed option(s) scripts < InputFile > output_file
sed -i option(s) scripts InputFile
파일을 처리하고 그 자리에서 수정합니다. 즉, 결과를 원본 파일로 다시 보냅니다.