Nhiều lệnh sed trong Bash


5

Tôi có một tên người dùng và mật khẩu tệp ở định dạng JSON mà tôi muốn chuyển đổi để xử lý.

Tôi đã sử dụng sedtrong các lệnh khác nhau để xử lý nó nhưng điều tôi muốn biết là làm thế nào để gộp cả ba lệnh thành một trong tương lai.

Định dạng gốc

    { "user.name1" : "hashed_password",
"user.name2" : "hashed_password" }

Kết quả mong muốn

user.name:hashed_password

Đây là những lệnh tôi đã chạy, tuy nhiên tôi đã không thể xâu chuỗi chúng lại với nhau bằng cách sử dụng đường ống hoặc chỉ đơn giản là nối chúng khi tôi gặp lỗi , sed: -e expression #1, char 8: unknown option to 's'.

Lệnh xúc phạm ...

sed -i 's/\"//g/s/\,/\n/g/\s//g' input_file 
sed: -e expression #1, char 8: unknown option to `s'

Làm thế nào các lệnh dưới đây có thể được nối thành một?

Các lệnh Xóa dấu ngoặc kép

sed -i 's/\"//g' input_file

Thay thế dấu phẩy bằng dòng mới

sed -i 's/\,/\n/g' input_file

Xóa khoảng trắng

sed -i 's/\s//g input_file

Câu trả lời:


18

Để đặt nhiều sedlệnh trong một " tập lệnh ", bạn có thể sử dụng nhiều -ecờ (có thể mang theo):

sed -i -e 's/\"//g' -e 's/\,/\n/g' -e 's/\s//g' input_file

Hoặc dấu phân cách dấu chấm phẩy (không có sẵn trên tất cả các cài đặt):

sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file

Bạn cũng sẽ cần thêm xử lý cho niềng răng - {}...


Đã nói điều này, để phân tích và xử lý JSON đúng cách, bạn thực sự không nên sử dụng sed... có lẽ hãy thử jq!

jq -r 'keys[] as $k | "\($k):\(.[$k])"' input_file

Đầu ra:

user.name1:hashed_password
user.name2:hashed_password
  • keys[] as $k sẽ lặp qua từng khóa lưu trữ giá trị của nó trong $k
    • ví dụ: user.name1,user.name2
  • "\($k):\(.[$k])"sẽ tạo thành một chuỗi, thay thế trong $k.[$k]
  • Việc sử dụng -rloại bỏ dấu ngoặc kép khỏi chuỗi đầu ra ( chế độ thô )

Sử dụng sedđể xử lý JSON sẽ mở ra cho bạn tất cả các loại vấn đề ... ví dụ: bạn sẽ xử lý như thế nào với đầu vào (JSON hoàn toàn hợp lệ) sau đây?

{
    "user.name1" :
        "hashed_password",
    "user.name2" :
        "hashed_password"
}

Nếu bạn muốn lệnh sed đầu tiên của mình thậm chí còn dễ mang theo hơn, bạn nên làm sed -i '' -e …để có được nó ngay trên BSD. Nếu không, bạn sẽ có một tệp sao lưu đã lưu có têninput_file-e
Tonin

3

Khi bạn đang xử lý đầu vào được tiêu chuẩn hóa như JSON, thông thường tốt hơn là sử dụng trình phân tích cú pháp phù hợp thay vì regex. Ví dụ: bạn sẽ chuyển đổi chính xác bất kỳ chuỗi thoát nào (mặc dù điều đó có thể không thực hiện được với dữ liệu đầu vào cụ thể của bạn!).

Thật không may, không có công cụ tuyệt vời nào để xử lý JSON trong coreutils. Attie cung cấp jq như một tùy chọn hợp lý nếu bạn tự do cài đặt các gói.

Nếu bạn không thể cài đặt các gói bổ sung, thì Python không khó lắm. Lấy kịch bản này làm ví dụ:

import json,sys
for (k, v) in json.load(sys.stdin):
    print(k + ":" + v)

Mà có thể được nén thành một dòng:

cat inputdata | python -c 'import json,sys;print("\n".join((k + ":" + v) for (k, v) in json.load(sys.stdin).items()))'

0

Đối với việc xóa ký tự đơn giản mà bạn đang thực hiện trong các sedlệnh này, thay vào đó tôi sẽ khuyên bạn nên sử dụng tr, với mục đích duy nhất là xóa, ép hoặc thay thế các ký tự riêng lẻ, bao gồm các dòng mới ( seddựa trên regex, thường dựa vào dòng mới làm dấu tách bộ đệm, vì vậy sử dụng sed để sửa đổi các dòng mới là khó khăn). Tôi nghĩ trlệnh này thực hiện mọi thứ bạn đang tìm kiếm:

cat json_filename | tr -d "{}\" \012\011\015" | tr "," "\012"

Đầu tiên trlệnh xóa niềng răng tất cả xoăn, hai dấu ngoặc kép, không gian, tự xuống dòng (bát phân 012, ascii 10), các tab (bát phân 011, ascii 9, và linefeed (bát phân 015, ascii 13) ký tự. Thứ hai trlệnh thay thế tất cả dấu phẩy với Vận chuyển trở lại. Miễn là tên và giá trị biến của tệp JSON của bạn không chứa dấu phẩy, các lệnh này sẽ cho phép bạn tránh cần một trình phân tích cú pháp JSON chuyên dụng.

Điều đó nói rằng, nếu bạn có một tập hợp các sedlệnh mà mỗi lệnh hoạt động độc lập, việc kết hợp chúng có thể được thực hiện dễ dàng nhất bằng cách sử dụng sedtùy chọn "-f" để đọc các lệnh riêng biệt từ một tệp. Bạn chỉ cần đặt các chuỗi s /.../.../ g vào một tệp, mỗi chuỗi trên một dòng riêng, sau đó chỉ định tên tệp đó sau tùy chọn "-f". Ví dụ: nếu ba sedlệnh bạn liệt kê là thỏa đáng, bạn có thể đặt chúng vào một tệp có tên "json.convert.sed" chỉ đơn giản chứa điều này:

s/\"//g 
s/\,/\n/g
s/\s//g

Sau đó, bạn sẽ gọi sedvới tệp lệnh này bằng cách sử dụng:

sed -f json.convert.sed

Điều đó nói rằng, các sedlệnh này không hoạt động để tôi thực hiện những gì bạn muốn và tôi không chắc bạn có thể sedsửa đổi các ký tự dòng mới. Điều này là do seddựa trên trình chỉnh sửa dòng "ed" cũ, được thiết kế để chỉnh sửa từng dòng một (phiên bản có thể sử dụng "tập lệnh" của nó), do đó, mỗi dòng đầu vào được "phân tích cú pháp" bằng cách sử dụng dòng mới làm dấu phân cách, sau đó dòng (không có dòng mới) được chuyển đến công cụ chỉnh sửa, các lệnh chỉnh sửa được áp dụng, sau đó dòng được chỉnh sửa được xuất với dòng mới. Sau đó vòng lặp lặp lại. Tôi chỉ có thể sử dụng sedđể sửa đổi dòng mới bằng cách thay đổi dòng mới thành một số ký tự riêng biệt (không xuất hiện trong đầu vào) bằng cách sử dụng tr. Cótrtrsẽ làm điều đó cho bạn. Nhưng nếu, chẳng hạn, bạn muốn chuyển đổi dòng mới thành dấu chấm phẩy có dấu cách, một cách để làm điều đó là:

cat input_file | tr "\012" "%" | sed "s/%/; /g"

(dòng mới được chuyển đổi thành% theo tr, sau đó sedchuyển đổi tất cả% ký tự thành các cặp ký tự ";".)


0

Sed có thể xử lý chỉnh sửa nhiều dòng, nhưng tôi đồng ý với Attie và Bob, phân tích cú pháp với sed regex có thể trở thành một cơn ác mộng.

sed -nr '/\{/ b Load ; d
: Load
/\}/ b Edit ; N ; b Load
: Edit ; s/[^"]+"([^"]+)"[^"]+"([^"]+)"(.*)/\1:\2\n\3/ ; t Print ; d
: Print ; P ; s/[^\n]+\n// ; t Edit' <<'eof'
{
    "user.name1" :
        "hashed_password1",
    "user.name2" :
        "hashed_password2"
}
    { "user.name3" : "hashed_password3",
"user.name4" : "hashed_password4" }

{ "user.name5":"hashed_password5"}
eof

user.name1:hashed_password1
user.name2:hashed_password2
user.name3:hashed_password3
user.name4:hashed_password4
user.name5:hashed_password5

-1

Bạn có thể kết hợp nó như thế này:

sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file

Bạn quên thêm việc loại bỏ {}. Vì vậy, bạn có thể muốn:

sed -i 's/\"//g;s/\,/\n/g;s/\s//g;s/{//g;s/}//g' input_file

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.