grep 명령을 사용하여 파일에서 전체 날짜를 추출할 수 있습니까?

grep 명령을 사용하여 파일에서 전체 날짜를 추출할 수 있습니까?

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. 액세스할 수 없는 경우 작업을 수락하지 마세요. 적절한 도구.xmlstarletxmllint


가장 진보된 명령줄 도구는 다음과 같습니다.xidel. 구문은 or보다 더 직관적이고 현대적입니다( XPath3다른 도구가 제한되는 경우 도 지원 XPath1). 다음을 참조하세요.xmlstarletxmllint

xidel -e '//item/@start' -s file.xml
20231010073000 +0100
  • -eXPath e표현 하는데 사용됨
  • -silent 의 경우 s(상태 정보 없음)

쿼리 언어는 XPathXML/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문자 시퀀스이며 첫 번째와 마지막도 삭제합니다).spacetabnewline

이 문제를 해결하는 방법에는 다음과 같은 여러 가지가 있습니다.

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 | looplastpipe$StartDate

답변3

XML을 다루고 있으므로 실제로 속성 값을 얻으려면 XML 파서를 사용해야 합니다.

start다음 명령을 사용하여 전체 문서의 모든 노드에서 속성 값을 가져오는 방법은 다음과 같습니다 .itemxmlstarlet

$ 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

관련 정보