簡體   English   中英

Linux Shell腳本問題

[英]A Linux Shell Script Problem

我在Linux Shell中有一個用點分隔的字符串,

$example=This.is.My.String

我想要

1.在最后一個點之前添加一些字符串,例如,我想在最后一個點之前添加“Good.Long”,所以我得到:

This.is.My.Goood.Long.String

2.獲取最后一個點后面的部分,這樣我就可以了

String

3.將點轉換為下划線除了最后一個點,所以我會得到

This_is_My.String

如果你有時間,請解釋一下,我還在學習正則表達式。

非常感謝!

我不知道'Linux Shell'是什么意思所以我會假設bash 此解決方案也適用於zsh等等

example=This.is.My.String
before_last_dot=${example%.*}
after_last_dot=${example##*.}
echo ${before_last_dot}.Goood.Long.${after_last_dot} 
This.is.My.Goood.Long.String

echo ${before_last_dot//./_}.${after_last_dot} 
This_is_My.String

臨時變量before_last_dotafter_last_dot應該解釋我對%##運算符的使用。 // ,我也認為是不言自明的,但我很樂意澄清你是否有任何問題。

這不使用sed (甚至是正則表達式),而是使用bash的內置參數替換。 我更喜歡每個腳本只使用一種語言,盡可能少的叉子:-)

  1. 這個的兩個版本:
    • 復雜: sed 's/\\(.*\\)\\([.][^.]*$\\)/\\1.Goood.Long\\2/'
    • 簡單: sed 's/.*\\./&Goood.Long./' - 謝謝Dennis Williamson
  2. 你想要什么?
    • 復雜: sed 's/.*[.]\\([^.]*\\)$/\\1/'
    • 更簡單: sed 's/.*\\.//' - 謝謝, 格倫傑克曼
  3. sed 's/\\([^.]*\\)[.]\\([^.]*[.]\\)/\\1_\\2/g'

使用3時,您可能需要至少兩次運行替換(完整)。

說明

請記住,在sed ,符號\\(...\\)是一個“捕獲”,可以在替換文本中引用為“ \\1 ”或類似內容。

  1. 將所有內容捕獲到一個字符串,以點開頭,后跟一系列非點(您也可以捕獲); 取代最后一個點之前的內容,新材料和最后一個點以及之后的內容。

  2. 忽略到最后一個點的所有內容,然后捕獲一系列非點; 僅用捕獲替換。

  3. 找到並捕獲一系列非點,一個點(未捕獲),然后是一系列非點和點; 用下划線替換第一個點。 這是全局完成的,但第二次和后續的匹配不會觸及已匹配的任何內容。 因此,我認為你需要ceil(log 2 N)次通過,其中N是要替換的點數。 一次通過處理1點替換; 兩次傳球處理2或3次; 三次傳球處理4-7,依此類推。

其他用戶已經為#1和#2提供了很好的答案。 #3的一些答案有一些缺點。 在一種情況下,您必須運行兩次替換。 另一方面,如果你的字符串有其他下划線,他們可能會被破壞。 此命令一次性工作,只影響點:

sed 's/\(.*\)\./\1\n./;h;s/[^\n]*\n//;x;s/\n.*//;s/\./_/g;G;s/\n//'
  1. 它通過插入換行符將最后一個點之前的行拆分並將結果復制到保留空間:

     s/\\(.*\\)\\./\\1\\n./;h 
  2. 從模式空間中的副本中刪除所有內容,包括換行符,並交換保留空間和模式空間:

     s/[^\\n]*\\n//;x 
  3. 從現在位於模式空間的副本中刪除包含換行符之后的所有內容

     s/\\n.*// 
  4. 將所有點更改為模式空間中副本中的下划線,並將保留空間附加到模式空間的末尾

     s/\\./_/g;G 
  5. 刪除追加操作添加的換行符

     s/\\n// 

然后完成sed腳本並輸出模式空間。

在每個編號步驟的末尾(一些包含兩個實際步驟):

步驟模式空間保持空間

  1. This.is.My \\n .String This.is.My \\n .String

  2. This.is.My \\n .String .String

  3. This.is.My .String

  4. This_is_My \\n .String .String

  5. This_is_My.String .String

這是一個使用Bash的正則表達式匹配(Bash 3.2或更高版本)的版本。

[[ $example =~ ^(.*)\.(.*)$ ]]
echo ${BASH_REMATCH[1]//./_}.${BASH_REMATCH[2]}

這是一個使用IFS (內部字段分隔符)的Bash版本。

saveIFS=$IFS
IFS=.
array=($e)                    # *   split the string at each dot
lastword=${array[@]: -1}
unset "array[${#array}-1]"    # *
IFS=_
echo "${array[*]}.$lastword"  #     The asterisk as a subscript when inside quotes causes IFS (an underscore in this case) to be inserted between each element of the array
IFS=$saveIFS

*在這些步驟之后使用declare -p array來查看數組的外觀。

1。

$ echo 'This.is.my.string' | sed 's}[^\.][^\.]*$}Good Long.&}'
This.is.my.Good Long.string

之前:一個點,然后沒有點直到結束。 之后:顯而易見,與第一部分相匹配

2。

$ echo 'This.is.my.string' | sed 's}.*\.}}'
string

sed貪婪的匹配,所以它會盡可能地擴展第一個閉包(。*),即延伸到最后一個點。

3。

$ echo 'This.is.my.string' | tr . _ | sed 's/_\([^_]*\)$/\.\1/'
This_is_my.string

將所有點轉換為_,然后將最后一個_轉換為點。

(警告:這會將'This.is.my.string_foo'變成'This_is_my_string.foo',而不是'This_is_my.string_foo')

你根本不需要正則表達式(那些復雜的東西會傷害我的眼睛!)如果你使用Awk並且有點創意。

1. echo $example| awk -v ins="Good.long" -F . '{OFS="."; $NF = ins"."$NF;print}'

這是做什么的:
-v ins =“Good.long”告訴awk創建一個名為'ins'的變量,其中包含“Good.long”作為內容,
-F 。 告訴awk使用點作為輸入字段的分隔符,
-OFS告訴awk使用點作為輸出的字段的分隔符,
NF是字段數,因此$ NF代表最后一個字段,
$ NF = ...部分替換最后一個字段,它將當前最后一個字符串追加到您要插入的內容(前面聲明的名為“ins”的變量)。

2. echo $example| awk -F . '{print $NF}'

$ NF是最后一個字段,所以就是這樣!

3. echo $example| awk -F . '{OFS="_"; $(NF-1) = $(NF-1)"."$NF; NF=NF-1; print}'

在這里,我們必須具有創造性,因為Awk AFAIK不允許刪除字段。 當然,我們將輸出字段設置為下划線或下划線。

$(NF-1)= $(NF-1)“。”$ NF:首先,我們將第二個最后一個字段替換為粘貼到倒數第二個字段的最后一個字段,其間有一個點。
然后,我們愚弄awk讓它認為字段數等於字段數減1,因此刪除最后一個字段!

注意你不能說$ NF =“”,因為它會顯示兩個下划線。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM