grep을 사용하여 Linux 시스템의 파일에서 파티션 날짜/시간을 추출하는 데 도움이 필요합니다.
소스 파일은 다음 데이터를 포함하는 XML입니다.
<item start="20231010073000 +0100" stop="20231010100000 +0100">...</item>
전체 시작 날짜를 추출해야 하지만 grep을 사용하면 전체 결과를 얻을 수 없습니다. 내 코드:
for startDate in $(grep -Eo 'start="[0-9]{14} [\+|\-][0-9]{4}"' "$filepath" ); do
echo "$startDate"
done
두 가지 다른 결과를 얻습니다.
start="20231010073000
+0100"
다음과 같이 얻을 수 있습니다.
start="20231010073000 +0100"
나는 및 다른 예제를 시도했지만 \s
동일한 [[:space:]]
솔루션을 사용했습니다.
내 코드에 버그가 있는 것 같지만 수정할 수 없습니다.
어떤 종류의 도움이라도 주시면 감사하겠습니다!
답변1
grep
사용 하거나 regex
구문 분석 하지 마십시오HTML/XML
원시 텍스트 줄을 처리하도록 설계된 도구를 사용하면 구조화된 텍스트(예: XML/HTML)를 구문 분석할 수 없으며 구문 분석할 수도 없습니다. XML/HTML을 처리해야 하는 경우 XML/HTML 파서를 사용하세요. 대부분의 언어에는 XML 구문 분석 지원 기능이 내장되어 있으며, 예를 들어 명령줄 셸에서 빠르게 작업을 수행해야 하는 경우 와 같은 특수 도구가 있습니다 xidel
. 액세스할 수 없는 경우 작업을 수락하지 마세요. 적절한 도구.xmlstarlet
xmllint
가장 진보된 명령줄 도구는 다음과 같습니다.xidel
. 구문은 or보다 더 직관적이고 현대적입니다( XPath3
다른 도구가 제한되는 경우 도 지원 XPath1
). 다음을 참조하세요.xmlstarlet
xmllint
xidel -e '//item/@start' -s file.xml
20231010073000 +0100
-e
XPath
e
표현 하는데 사용됨-s
ilent 의 경우s
(상태 정보 없음)
쿼리 언어는 XPath
XML/HTML을 구문 분석하는 여러 상황에서 유용합니다.
XPath
지도 시간:
https://developer.mozilla.org/en-US/docs/Web/XPath
http://www.w3schools.com/xpath/xpath_functions.asp
http://stackoverflow.com/tags/xpath/info
https://topswagcode.com/xpath/(인터랙티브 XPath
게임, 기본이 갖춰져 있고 인터랙티브하게 연습하고 싶을 때)
답변2
문제는 루프에 있습니다. 기본적으로 분할됩니다 $IFS
(기본값은 임의 또는 $IFS
문자 시퀀스이며 첫 번째와 마지막도 삭제합니다).space
tab
newline
이 문제를 해결하는 방법에는 다음과 같은 여러 가지가 있습니다.
while IFS= read -r StartDate; do
echo "$StartDate"
done < <(grep -Eo -- 'start="[0-9]{14} [+-][0-9]{4}"' "$filepath")
( 옵션이 활성화되지 않은 경우 bash 쉘의 경우처럼 루프가 하위 쉘이 아닌 현재 쉘에 있도록 하기 위해 : loop < <( command generating the input )
대신 : 형식을 사용합니다 . 항상 필요한 것은 아니지만 예를 들어 루프 후에 보고 싶은 최신 값 : 서브셸에 있는 경우 해당 값은 서브셸 끝에서 사라지며 현재 셸에서 검색할 수 없습니다.command generating the input | loop
lastpipe
$StartDate
답변3
XML을 다루고 있으므로 실제로 속성 값을 얻으려면 XML 파서를 사용해야 합니다.
start
다음 명령을 사용하여 전체 문서의 모든 노드에서 속성 값을 가져오는 방법은 다음과 같습니다 .item
xmlstarlet
$ xmlstarlet select --template --value-of '//item/@start' --nl file
20231010073000 +0100
또는 축약된 옵션 이름을 사용하십시오.
$ xmlstarlet sel -t -v '//item/@start' -n file
20231010073000 +0100
노드 가 여러 개 있고 첫 번째 노드의 속성 값만 item
필요한 경우 XPath 쿼리에서 이를 사용합니다.start
//item[1]/@start
그런 다음 표준 명령 대체를 사용하여 결과를 변수로 전송할 수 있습니다.
start=$( xmlstarlet sel -t -v '//item[1]/@start' file )
( -n
더 이상 필요하지 않기 때문에 위 명령에서 해당 옵션을 제거했습니다. 출력 끝에 개행 문자를 추가하지만 명령 대체는 이를 제거합니다.)
bash
또는 다음을 사용하여 모든 항목을 배열로 읽을 수 있습니다 readarray
.
readarray -t startarray < <(
xmlstarlet sel -t -v '//item/@start' -n file
)
그런 다음 반복하거나( ) for start in "${startarray[@]}"; do ...; done
출력을 직접 반복합니다.xmlstarlet
while IFS= read -r start; do
# ...
done < <( xmlstarlet ...as above... )
답변4
XML을 올바르게 구문 분석하기 위해 시스템에 추가 종속성을 설치할 수 없는 경우 한 줄로 수행하는 대신 구문 분석을 보다 우아하게 처리하는 스크립트를 작성하겠습니다.
다음은 귀하가 제공한 줄에서 해당 시간을 구문 분석하는 샘플 스크립트입니다.
#!/usr/bin/env bash
INPUT_FILE="$1"
TIME_FILTER='[0-9]*\s(\+|\-)[0-9]*'
__getStart(){
line="$1"
echo "$line" | egrep -o "start=\"${TIME_FILTER}\"" | egrep -o "$TIME_FILTER"
}
__getStop(){
line="$1"
echo "$line" | egrep -o "stop=\"${TIME_FILTER}\"" | egrep -o "$TIME_FILTER"
}
while IFS= read -r line; do
start_time="$(__getStart "$line")"
stop_time="$(__getStop "$line")"
echo "Start Time: ${start_time}"
echo "Stop Time: ${stop_time}"
done < "$INPUT_FILE"
이런 식으로 스크립트를 사용할 수 있습니다
[/var/tmp] $ ./get-dates.sh date-extraction.xml
Start Time: 20231010073000 +0100
Stop Time: 20231010100000 +0100