Làm thế nào để tách nhiều không gian thành một bằng cách sử dụng sed?


69

sedtrên AIX không làm những gì tôi nghĩ nó nên. Tôi đang cố gắng thay thế nhiều không gian bằng một khoảng trống trong đầu ra của IOSTAT:

# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty:      tin         tout    avg-cpu: % user % sys % idle % iowait
          0.2         31.8                9.7   4.9   82.9      2.5

Disks:        % tm_act     Kbps      tps    Kb_read   Kb_wrtn
hdisk9           0.2      54.2       1.1   1073456960  436765896
hdisk7           0.2      54.1       1.1   1070600212  435678280
hdisk8           0.0       0.0       0.0          0         0
hdisk6           0.0       0.0       0.0          0         0
hdisk1           0.1       6.3       0.5   63344916  112429672
hdisk0           0.1       5.0       0.2   40967838  98574444
cd0              0.0       0.0       0.0          0         0
hdiskpower1      0.2     108.3       2.3   2144057172  872444176

# iostat | grep hdisk1
hdisk1           0.1       6.3       0.5   63345700  112431123

#iostat|grep "hdisk1"|sed -e"s/[ ]*/ /g"
 h d i s k 1 0 . 1 6 . 3 0 . 5 6 3 3 4 5 8 8 0 1 1 2 4 3 2 3 5 4

sed nên tìm kiếm và thay thế (nhiều) nhiều khoảng trắng (/ [] * /) bằng một khoảng trắng (/ /) cho toàn bộ nhóm (/ g) ... nhưng nó không chỉ làm điều đó ... cách nhau từng ký tự.

Tôi đang làm gì sai? Tôi biết nó phải đơn giản ... AIX 5300-06

chỉnh sửa: Tôi có một máy tính khác có hơn 10 ổ cứng. Tôi đang sử dụng điều này như là một tham số cho một chương trình khác cho mục đích giám sát.

Vấn đề tôi gặp phải là "awk '{print $ 5}' không hoạt động vì tôi đang sử dụng $ 1, v.v. trong giai đoạn thứ cấp và đã gặp lỗi với lệnh In. Tôi đang tìm phiên bản grep / sed / cut Những gì dường như làm việc là:

iostat | grep "hdisk1 " | sed -e's/  */ /g' | cut -d" " -f 5

Các [] là "0 trở lên" khi tôi nghĩ chúng có nghĩa là "chỉ một". Loại bỏ các dấu ngoặc đã làm cho nó hoạt động. Ba câu trả lời rất hay thực sự nhanh chóng khiến bạn khó chọn "câu trả lời".

Câu trả lời:


52

Việc sử dụng greplà dư thừa, sedcó thể làm tương tự. Vấn đề là trong việc sử dụng *trận đấu đó cũng có 0 khoảng trắng, bạn phải sử dụng \+thay thế:

iostat | sed -n '/hdisk1/s/ \+/ /gp'

Nếu bạn sedkhông hỗ trợ \+metachar, thì hãy làm

iostat | sed -n '/hdisk1/s/  */ /gp'

AIX dường như không hỗ trợ +, nhưng việc loại bỏ [] dường như đã thực hiện được mánh khóe.
WernerCD

Tôi đã thử sử dụng phiên bản sed -n ... điều xảy ra là tôi có một máy tính khác có hơn 10 ổ đĩa để nó bắt đầu thực hiện 1, 10, 11, v.v ... Tôi đã thử thêm một khoảng trắng / hdisk1 / và nó đã cho tôi một "chức năng không được công nhận". những gì có vẻ hoạt động là >> iostat | grep "hdisk1" | sed -e's / * / / g '
WernerCD

67

/[ ]*/khớp không hoặc nhiều khoảng trắng, do đó, chuỗi trống giữa các ký tự khớp.

Nếu bạn đang cố gắng khớp "một hoặc nhiều khoảng trắng", hãy sử dụng một trong các dấu cách sau:

... | sed 's/  */ /g'
... | sed 's/ \{1,\}/ /g'
... | tr -s ' '

À ... [] làm cho nó "tùy chọn". Giải thích nó.
WernerCD

5
@WernerCD, không *làm cho nó "tùy chọn". [ ]chỉ cần tạo một danh sách các ký tự chỉ có một ký tự trong đó (một khoảng trắng). Đó là bộ định lượng *có nghĩa là "không hoặc nhiều hơn những thứ trước đó"
glenn jackman

À ... để chính xác hơn, thay đổi nó từ một không gian duy nhất / * /, thành một không gian kép là điều đã làm sau đó. Tôi gottcha.
WernerCD

Tôi đã cố gắng tìm kiếm một mẫu chỉ tìm kiếm hai không gian và nó hoạt động rất tuyệt
minhas23

6
+1 cho tr -s ' 'giải pháp đơn giản nhất
Andrejs

12

Thay đổi *toán tử của bạn thành a +. Bạn phù hợp với 0 hoặc nhiều ký tự trước đó, khớp với mọi ký tự bởi vì mọi thứ không phải là khoảng trắng là ... ừm ... không có không gian. Bạn cần phải khớp MỘT hoặc nhiều hơn. Trên thực tế sẽ tốt hơn nếu kết hợp hai hoặc nhiều hơn

Lớp ký tự được đặt trong ngoặc cũng không cần thiết để khớp một ký tự. Bạn chỉ có thể sử dụng:

s/  \+/ /g

... Trừ khi bạn muốn khớp các tab hoặc các loại khoảng trắng khác, thì lớp nhân vật là một ý tưởng hay.


AIX dường như không hỗ trợ +.
WernerCD

1
@WernerCD: Sau đó thử s/ */ /g(với ba khoảng trắng, định dạng nhận xét đang thu gọn chúng). Toán tử sao sẽ làm cho ký tự trước đó là tùy chọn, vì vậy, nếu bạn ghép hai hoặc nhiều hơn với ký tự đó, bạn cần tự khớp hai ký tự đầu tiên (hai khoảng trắng) sau đó thêm khoảng trắng thứ ba và dấu sao để tạo khoảng trắng thứ ba và không gian tiếp theo.
Caleb

3
@userunknown: Thật ra tôi không pha trộn hai thứ, mọi người đều vậy :) Thay thế một không gian bằng một không gian duy nhất là vô nghĩa, bạn chỉ cần thực hiện hành động này trên các trận đấu có ít nhất hai không gian liên tiếp. Hai khoảng trống và một cộng hoặc ba khoảng trống và một ngôi sao là chính xác những gì cần thiết.
Caleb

@userunknown: Nó không phải là vấn đề lớn, nó chỉ lãng phí một chút thời gian xử lý và nó ném đi những thứ như máy đếm diêm.
Caleb

8

Bạn luôn có thể kết hợp lần xuất hiện cuối cùng trong một chuỗi bất kỳ thứ gì như:

s/\(sequence\)*/\1/

Và vì vậy, bạn đang đi đúng hướng, nhưng thay vì thay thế chuỗi bằng một khoảng trắng - thay thế nó bằng lần xuất hiện cuối cùng - một khoảng trắng. Theo cách đó, nếu một chuỗi các không gian được khớp thì chuỗi đó được giảm xuống một khoảng trắng , nhưng nếu chuỗi null được khớp thì chuỗi null được thay thế bằng chính nó - và không có hại, không có lỗi. Ví dụ:

sed 's/\( \)*/\1/g' <<\IN                                    
# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty:      tin         tout    avg-cpu: % user % sys % idle % iowait
          0.2         31.8                9.7   4.9   82.9      2.5

Disks:        % tm_act     Kbps      tps    Kb_read   Kb_wrtn
hdisk9           0.2      54.2       1.1   1073456960  436765896
hdisk7           0.2      54.1       1.1   1070600212  435678280
hdisk8           0.0       0.0       0.0          0         0
hdisk6           0.0       0.0       0.0          0         0
hdisk1           0.1       6.3       0.5   63344916  112429672
hdisk0           0.1       5.0       0.2   40967838  98574444
cd0              0.0       0.0       0.0          0         0
hdiskpower1      0.2     108.3       2.3   2144057172  872444176

# iostat | grep hdisk1
hdisk1           0.1       6.3       0.5   63345700  112431123

IN

ĐẦU RA

# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty: tin tout avg-cpu: % user % sys % idle % iowait
 0.2 31.8 9.7 4.9 82.9 2.5

Disks: % tm_act Kbps tps Kb_read Kb_wrtn
hdisk9 0.2 54.2 1.1 1073456960 436765896
hdisk7 0.2 54.1 1.1 1070600212 435678280
hdisk8 0.0 0.0 0.0 0 0
hdisk6 0.0 0.0 0.0 0 0
hdisk1 0.1 6.3 0.5 63344916 112429672
hdisk0 0.1 5.0 0.2 40967838 98574444
cd0 0.0 0.0 0.0 0 0
hdiskpower1 0.2 108.3 2.3 2144057172 872444176

# iostat | grep hdisk1
hdisk1 0.1 6.3 0.5 63345700 112431123

Tất cả những gì đã nói, có lẽ tốt hơn nhiều để tránh regexps hoàn toàn trong tình huống này và thay vào đó:

tr -s \  <infile

4
+1 vì sự đơn giản của câu trả lời thực sự,iostat | tr -s \
Wildcard

'tr -s \' giống với 'tr -s ""'. Làm cho tôi nhận ra rằng không gian có thể được chuyển qua như một đối số trong chuỗi bằng cách thoát với "\". Tôi thấy rằng nó cũng có thể được sử dụng trong shell script. Ứng dụng tuyệt vời.
randominstanceOfLivingThời gian

5

Lưu ý rằng bạn cũng có thể làm những gì bạn cố gắng, đó là

iostat | grep "hdisk1 " | sed -e's/  */ /g' | cut -d" " -f 5

bởi

iostat | while read disk tma kbps tps re wr; do [ "$disk" = "hdisk1" ] && echo "$re"; done

điều này có thể đặc biệt hữu ích nếu sau này bạn cũng cố gắng truy cập vào các trường khác và / hoặc tính toán một cái gì đó - như thế này:

iostat | while read disk tma kbps tps re wr; do [ "$disk" = "hdisk1" ] && echo "$(( re/1024 )) Mb"; done

Rất đẹp. Phiên bản đầu tiên hoạt động. Các hộp AIX của tôi dường như không thích hộp thứ hai. Tất cả ba hộp đầu ra: "$ [re / 1024] Mb". Công cụ giám sát tôi đang sử dụng có các chuyển đổi cho các báo cáo vì vậy nó không phải là thứ "cần thiết" đối với tôi, nhưng tôi thích nó.
WernerCD

@enzotib Cảm ơn bạn đã sửa lỗi while.
rozcietrzewiacz

@WernerCD Ah, điều này $[ .. ]có thể có sẵn trong các phiên bản gần đây của bash (có thể là zsh nữa). Tôi đã cập nhật câu trả lời cho một di động hơn $(( .. ))thay thế.
rozcietrzewiacz

Điều đó đã lừa Tôi sẽ phải tìm kiếm điều đó. Ngạc nhiên.
WernerCD

0

Bạn có thể sử dụng tập lệnh sau để chuyển đổi nhiều khoảng trắng thành một khoảng trắng, TAB hoặc bất kỳ chuỗi nào khác:

$ ls | compress_spaces.sh       # converts multiple spaces to one
$ ls | compress_spaces.sh TAB   # converts multiple spaces to a single tab character
$ ls | compress_spaces.sh TEST  # converts multiple spaces to the phrase TEST
$ compress_spaces.sh help       # show the help for this command

nén_spaces.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: {REPLACE_WITH}

  NOTE: If you pass in TAB, then multiple spaces are replaced with a TAB character

  no args -> multiple spaces replaced with a single space
  TAB     -> multiple spaces replaced with a single tab character
  TEST    -> multiple spaces replaced with the phrase "TEST"

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show help if we're not getting data from stdin
if [ -t 0 ]; then
  show_help
fi

REPLACE_WITH=${1:-' '}

if [ "$REPLACE_WITH" == "tab" ]
then
  REPLACE_WITH=$'\t'
fi
if [ "$REPLACE_WITH" == "TAB" ]
then
  REPLACE_WITH=$'\t'
fi

sed "s/ \{1,\}/$REPLACE_WITH/gp"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.