bash - "테이블" 값을 배열의 문자열로 분리합니다.

bash - "테이블" 값을 배열의 문자열로 분리합니다.

편집: 죄송합니다. 제가 주장한 결과가 잘못되었습니다. 이전에 생각했던 것보다 더 많은 공백이 있습니다(이러한 공백을 제거하기 위해 출력을 html 파일에 저장했을 때 문제가 발생했습니다). 실제 출력은 다음과 같습니다.

user@Debian:~$ sudo smartctl -l selftest /dev/sda | grep -e "#"
# 1  Short offline       Completed without error       00%      7264         -
# 2  Short offline       Completed without error       00%      7240         -
# 3  Short offline       Completed without error       00%      7219         -
# 4  Short offline       Completed without error       00%      7192         -
# 5  Short offline       Completed without error       00%      7168         -
# 6  Short offline       Completed without error       00%      7144         -
# 7  Extended offline    Completed without error       00%      7125         -
# 8  Short offline       Completed without error       00%      7096         -
# 9  Short offline       Completed without error       00%      7072         -
#10  Short offline       Completed without error       00%      7049         -
#11  Short offline       Completed without error       00%      7004         -

나는 Linux/bash를 처음 접했기 때문에 올바른 용어를 사용하고 있는지 잘 모르겠습니다.

어쨌든 저는 SMART 오류가 있는지 감지하고 알려주기 위해 Smartmontools를 사용하고 있습니다. 내가 원하는 방식으로 작동하지만 HDD에 대한 일일 통계를 얻고 싶었기 때문에 smartmontools 및 임시, SMART 값, 사용된 HDD 공간과 같은 기타 흥미로운 항목에서 정보를 수집하는 스크립트를 직접 만들었습니다. 아마도 이와 같은 일을 하는 가장 좋은 방법은 아닐 것입니다. 하지만 저는 이 일을 즐기며 계속해서 배우고 있습니다.

내가 보낸 이메일은 표를 만들고 긍정적/부정적 결과에 글꼴 색상(녹색/빨간색)을 추가하기 위해 HTML 형식으로 작성되었습니다. 그런데 자가 테스트를 표시하기 위한 테이블을 만들려고 하면 몇 가지 문제가 발생합니다.

내가 사용하는 명령은 다음과 같습니다. ( sudo smartctl -l selftest $HDD | grep '#' >> $SMARTFILE루프에서 $HDD는 내 시스템의 모든 HDD이고 $SMARTFILE은 내가 저장하는 html 파일입니다.

이 명령의 출력은 다음과 같습니다.

#1 간략한 오프라인이 오류 없이 완료되었습니다. 00% 7264 -

#2 오류 없이 간략한 오프라인 완료 00% 7240 -

등. 다음 코드를 사용하여 드라이브의 일련 번호를 얻습니다.

HDDinfo="$(sudo smartctl --info $HDD | grep -e 'Serial Number')"
IFS=':' read -r -a array <<< "$HDDinfo"

sudo smartctl --info $HDD | grep -e 'Serial Number'정상적으로 출력되기 때문에

일련 번호: WD-RESTOFS/N123

하지만 이를 테이블에 넣기 위해 ":" 문자를 사용하여 문자열을 구분하고 다음과 같은 배열을 얻었습니다.

일련 번호, WD-RESTOFS/N123

그러나 내가 얻고 있는 출력에는 sudo smartctl -l selftest $HDD | grep '#' >> $SMARTFILE그것들을 분리할 확실한 방법이 없으며 이전에 했던 방식은 작동하지 않습니다. 왜냐하면 내가 원하는 문자열에 공백이 있어서 다음을 사용하여 분리할 수 없기 때문입니다. 공백 문자.

TL;DR, 다음 명령이 있고 sudo smartctl -l selftest /dev/sda | grep '#' >> $SMARTFILE그 출력은 다음과 같습니다.

#1 간략한 오프라인이 오류 없이 완료되었습니다. 00% 7264 -

#2 오류 없이 간략한 오프라인 완료 00% 7240 -

다음과 같이 개별적으로 저장하기 위해 배열(또는 유사한 배열)을 만들고 싶습니다.

# 1, 일시적으로 오프라인, 오류 없이 완료됨, 00%, 7264, -

이렇게 하면 HTML 테이블에 쉽게 넣을 수 있습니다. 이것이 가능합니까? 오류가 발생하면 다음과 같이 나타날 수 있습니다.

#1 짧은 오프라인 완료: 읽기 실패 20% 717 555027747

불분명하거나 추가 정보가 필요한 경우 알려주시기 바랍니다.

답변1

위의 (작은) 메시지 샘플에서 smartctl해당 부분은 본질적으로 "<space><소문자를 제외한 모든 것>"(줄 시작 부분의 "#nnn" 필드 제외)으로 구분된 것처럼 보입니다.

sed부품을 분리하는 데 도움이 될 수 있습니다.

$ smartctl_output="\                                           
# 1 Short offline Completed without error 00% 7264 -
# 2 Short offline Completed without error 00% 7240 -
# 1 Short offline Completed: read failure 20% 717 555027747"

$ csv="$( sed 's/ //; s/ \([^[:lower:]]\)/,\1/g' <<< "$smartctl_output" )"

$ echo "$csv"
#1,Short offline,Completed without error,00%,7264,-
#2,Short offline,Completed without error,00%,7240,-
#1,Short offline,Completed: read failure,20%,717,555027747

이것이 원하는 것이라면 이제 HDDinfo에서와 마찬가지로 어레이를 채울 수 있습니다.

[고쳐 쓰다]

sed분할을 수행하는 부분에 대한 설명은 다음과 같습니다. sed프로그램은 한 줄에 배치한 두 부분으로 구성됩니다. 확장 버전은 다음과 같습니다.

sed '
    s/ //
    s/ \([^[:lower:]]\)/,\1/g
'

프로그램은 sed입력의 각 행에 대해 작동합니다. 즉, 행을 읽고 일련의 변환을 적용한 다음 해당 행을 인쇄합니다. 그런 다음 더 이상 읽을 줄이 없을 때까지 다음 줄부터 시작합니다.

여기서 첫 번째 sed명령은 s/ //"#"과 다음 숫자를 함께 넣기 위해 첫 번째 공백을 제거합니다.

그런 다음 두 번째 sed명령은 s/ \([^[:lower:]]\)/,\1/g각 필드의 시작 부분("<space><소문자를 제외한 모든 것>"으로 정의됨)을 검색하고 공백을 콜론으로 바꿉니다. 다음 필드의 첫 번째 문자를 나타내는 \1대괄호 " " 사이의 정규식을 참조합니다 .\([^[:lower:]]\)

나머지 부분은 테스트입니다. sed파일의 내용이나 명령의 출력을 입력하는 대신 변수 smartctl_output(샘플로 구성된 문자열)를 입력하고 그 csv변수에 결과를 할당합니다.

[업데이트#2]

이제 필드가 두 개 이상의 공백으로 구분된 것으로 보입니다. 이전보다 훨씬 쉬워졌습니다. 명령은 sed다음과 같습니다.

sed 's/  \+/,/g'

즉, 두 개 이상의 공백으로 구성된 모든 계열을 콜론으로 바꿉니다.

답변2

쉘에서 로컬로 이 작업을 수행하는 방법이 생각나지 않지만 perl예를 들어 다음을 정의할 수 있습니다.정규식필드 분할을 위해 이를 사용하여 원하는 단일 구분 기호를 삽입한 다음 IFS=,다른 방법을 사용하여 간단히 읽을 수 있습니다.

귀하의 예에 따라 필드는 공백으로 구분되고 그 뒤에 다음이 올 수 있습니다.

  1. 대문자 또는 하이픈
  2. 적어도 두 개의 숫자로 구성된 시퀀스

그러니 명령을 파이프하세요.

. . . | 
  perl -F'[[:space:]](?=[[:upper:]-]|[[:digit:]]{2,})' -anle 'print join ",", @F'

관련 정보