Neden sed expr1 | sed expr2`den farklı sed -e expr1 -e expr2`


10

idBir kullanıcının üyesi olduğu grupların daha okunabilir bir satır liste listesi sağlamak için çıktıyı bölüyordum :

id roaima | sed 's/,/\n\t/g'
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima)
    24(cdrom)
    25(floppy)
    ...
    822413650 (international (uk) location)

Grup numarasını köşeli ayraçlı adından ayırmak istedim, böylece ifadeyi böyle genişlettim

id roaima | sed -e 's/,/\n\t/g' -e '2,$s/(/ (/'

Ancak, başlangıçta beklediğim gibi olmadı. İkinci ifadenin bir etkisi olmadığı görülmüştür.

Bunun yerine, istediğim sonucu elde etmek için sed, şu gibi iki ayrı komut çalıştırmam gerekiyordu :

id roaima | sed -e 's/,/\n\t/g' | sed '2,$s/(/ (/'
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima)
    24 (cdrom)
    25 (floppy)
    ...
    822413650 (international (uk) location)

Neden sedbirden fazla talimat içeren bir boru yerine iki komutta iki komuta ihtiyacım var ? Veya bunu biriyle yapabilirsem, bunu sednasıl yapardım?

Özellikle istediğim, her bir öğe için UID / GID değeri ve parantez adı arasındaki tek boşluğa sahip olmaktır (ilk satırdaki UID ve GID'ler dahil), ancak uyarı, gerçek verilerimde gruplara sahip olabileceğimdir. isimlerinde parantez içeren ve isimlerin kendilerinin karıştırılmasını istemiyorum.

Yanıtlar:


14

sed, awkveya her satırda birbiri ardına ayrı ayrı cutveya gibi perl -neçalışır.

sed -e code1 -e code2

aslında şu şekilde çalıştırılır:

while(patternspace = getline()) {
  linenumber++
  code1
  code2
} continue {print patternspace}

Kod2'niz buysa 2,$ s/foo/bar/, bu:

if (linenumber >= 2) sub(/foo/, "bar", patternspace)

Girişinizde yalnızca bir satır olduğundan, sub()hiçbir zaman çalıştırılmaz.

İçinde desen alanına yeni satır karakterleri eklemek artış code1yapmaz linenumber.

Bunun yerine, ilk ve tek girdi satırını işlerken içinde birkaç satır bulunan bir desen alanınız vardır . İkinci satırda ve bu çok satırlı desen alanının üzerinde değişiklik yapmak istiyorsanız, aşağıdakine benzer bir şey yapmanız gerekir:

s/\(\n[^(]*\)(/\1 (/g

Tabii burada olsa da, aynı anda iki işlemi de yapabilirsiniz:

id | sed 's/,\([^(]*\)(/\n\t\1 (/g'

awk ve perl -n / p, bir satırın varsayılanı olan ancak değiştirilebilen her kayıt üzerinde çalışır ; bu durumda -vRS=,veya -054yardımcı olabilir.
dave_thompson_085

5

GNU sed'iniz varsa,

id username | sed 's/(/ (/4g; s/,/\n\t/g'

4. ve sonraki açık parantezlerin önüne boşluk ekler, ardından virgüllerin yerini alır.


1
İlginç görünüyor. Ne yazık ki, adımın içine international (uk) locationistenmeyen bir boşluk ekleyerek , örneğim gibi parantez içeren grup adlarını da etkiler .
roaima

Ardından s/\([[:digit:]]\+\)(/\1 (/4g, yalnızca parantezden önce rakamlar varsa boşluk ekleyecek olanı kullanın .
glenn jackman

1

@ Stéphane-chazelas'ın söyledikleri doğrudur, ancak her zaman önce alanı ekleyebilir ve bundan sonra satırlara ayırabilirsiniz:

sed -e 's:\([,=][0-9]*\):\1 :g' -e 's:,:\n\t:g'

Veya tek bir sed komut dosyasında (olmadan -e):

sed 's:\([,=][0-9]*\):\1 :g; s:,:\n\t:g'

Normalde /komut arama (lar) ının ayırıcısı olarak " " kullanırız , ancak herhangi bir karakteri de kabul eder, bu nedenle bazen " :" gibi kombinasyonlardan kaçınmak için " " gibi diğer karakterleri kullanarak okumak daha kolaydır /\.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.