[問題] 這個 sed-縮網址程式何時會爆炸?

看板Linux作者 (cuello)時間3年前 (2020/11/04 06:52), 3年前編輯推噓10(10043)
留言53則, 8人參與, 3年前最新討論串1/3 (看更多)
#!/bin/sh # # 1604436674 created for testing in Linux/PTT # # 這是個 YouTube 縮網址的 one-liner. 必須很 portable. # 我已測試過各種不同形狀的水管 url's 例如: # # /v/<VID> # watch?v=<VID> # embed/<VID>?rel=0 # watch?argv=xyz&v=<VID> # watch?v=<VID>&list=PLDB852818BF378DAC # watch?v=<VID>&feature=related # watch?argv=xyz&v=<VID> # watch?v=<VID>&feature=feedrec_grec_index # user/IngridMichaelsonVEVO#p/a/u/1/<VID> # v/<VID>?fs=1&amp;hl=en_US&amp;rel=0 # watch?v=<VID>#t=0m10s # embed/<VID>?rel=0 # watch?v=<VID> # http://youtu.be/<VID> (idempotent) # # 能不能幫忙看看還有哪些 url's 會出錯, 並幫忙想辦法? # # 我本來不喜歡縮網址的, 因為不知道有效期限多久... # 但如果我沒誤解的話, youtu.be 是水管自家的, # 而且保留了原始的影片 ID (確定都是11個字嗎?). # 所以還可以接受. # # 解說: # # 0. 它必須儘可能 portable, 不管甚麼系統, 必須隨抄即用 # 誰有 Solaris, SunOS, OsX, Ultrix, AIX, ... 拜託! # 我只是很好奇, 它能有多廣的 portability. # # 1. 請忽視與 termux 有關的東西, 那是讓手機也可以用的, # # 2. youtu() 就已經是個充份的 one-liner. # 為了應付可能出現的雜七雜八的選項及形態 # 我決定擷取 \1. protocol 跟 \2. video_id # 然後忽略掉其它可能出現的所有東西. # # 3. 為方便測試, 所以它要可以從 X-clipborad 讀取, # 由 stdin 讀取, 也可以由指令行讀取. # # 4. 用了 sed(1) tr(1) grep(1) xsel(1) termux-clipboard-get(1) # # 5. 1604555294 新增, 原本的 -e 's/$/\n/' | tr -s '\n' 是為了確保 # 行尾起碼有一個 newline, 而且只有一個. 這也是為了使用上方便. youtu() { # sed -e 's|^\(http.\?\):.*[/vd]\{0,1\}[0-9vd][/=]\([0-9a-zA-Z_-]\{11\}\).*$|\1://youtu.be/\2|' -e 's/$/\n/' | tr -s '\n' # 哇-- 這行那麼長不知道會不會壞掉.... # # 1604555294 更新, 上面那一行到 FreeBSD 就燒了, 先斷成兩行吧 (lantw44) # sed 's|^\(http[s]\{0,1\}\):.*[/vd]\{0,1\}[0-9vd][/=]\([0-9a-zA-Z_-]\{11\}\).*$|\1://youtu.be/\2\ #|' | tr -s '\n' # 1604671459 找了 awk 幫忙來確保 one & only one newline sed 's|^\(http[s]\{0,1\}\):.*[/vd]\{0,1\}[0-9vd][/=]\([0-9a-zA-Z_-]\{11\}\).*$|\1://youtu.be/\2|' | awk 1 } if [ -t 0 ] # priority: stdin > "$1" > X-clipboard then # echo "$HOME" | grep -q termux && XGET="termux-clipboard-get" || XGET="xsel" # [ "$1" ] && echo "$1" | youtu || $XGET | youtu # 1604570722 還是改一下吧, 以上兩行是錯的, A && B || C 不是 if-then-else # (contributors: lantw44 rickieyang bitlife) # if echo "$HOME" | grep -q termux # then # XGET="termux-clipboard-get" # else # XGET="xsel" # fi # # if [ "$1" ] # then # echo "$1" | youtu # else # $XGET | youtu # fi # 1604671459 讓它在 Mac 上也會動 (rickieyang) if [ "$1" ] then echo "$1" | youtu else # termux > Mac > X11 XGET="xsel" uname | grep -q "Darwin" && XGET="pbpaste" echo "$HOME" | grep -q "termux" && XGET="termux-clipboard-get" $XGET | youtu fi else youtu fi -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.167.174.150 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Linux/M.1604443935.A.A5C.html

11/04 09:04, 3年前 , 1F
還沒看完,不過要大量用到Regex的話,sed建議加-E
11/04 09:04, 1F

11/04 09:05, 3年前 , 2F
這樣很多地方就不用加反斜線了
11/04 09:05, 2F

11/04 09:18, 3年前 , 3F
然後我會這樣寫:
11/04 09:18, 3F

11/04 09:18, 3年前 , 4F
sed -Ee 's@(http|https)://.*[/=]([0-9a-zA-Z_-]{11})
11/04 09:18, 4F

11/04 09:19, 3年前 , 5F
.*@\1://youtu.be/\2@'
11/04 09:19, 5F

11/04 09:19, 3年前 , 6F
如果確定都是11碼後9碼以上,vd那段其實不用加
11/04 09:19, 6F

11/04 09:26, 3年前 , 7F
或者也可以把{11}改成{11,}
11/04 09:26, 7F
多謝,我看我們還是先照顧跨平台適應性吧 另外,那段很醜的 vd 甚麼, 是 ad hoc 應付後面雜雜八的水管選項 否則好像過不了關, 你有試過可以嗎? 另外,我也不確定 http 會不會出現大寫 HTTP...

11/04 09:27, 3年前 , 8F
你要找何時會爆是要找實務上可見的,還是故意弄出會爆但實
11/04 09:27, 8F

11/04 09:28, 3年前 , 9F
務上不(太可能)會出現的?
11/04 09:28, 9F
基本上,先照料實務上尚未預見的狀況好了 i.e. 火箭升空自爆的狀況,先不管是否有外星人故意推它 來看看,擺在這裡一個月,是否可能弄堅固一點 讓它可以拿到任何認得 #!/bin/sh 的地方就跑 也讓我多長點見識

11/05 00:03, 3年前 , 10F
shell script 部分的 portability 可以先跑 shellcheck
11/05 00:03, 10F

11/05 00:04, 3年前 , 11F
看看有沒有問題,而一樓說的 sed -E 在 POSIX 沒有,所以
11/05 00:04, 11F

11/05 00:05, 3年前 , 12F
可以猜想如果有的系統只做 POSIX 那就不能用 sed -E。
11/05 00:05, 12F

11/05 00:08, 3年前 , 13F
實際測試這個 script 在 FreeBSD 執行成功但結果有誤,因
11/05 00:08, 13F

11/05 00:09, 3年前 , 14F
為 FreeBSD 的 sed 不支援 \? 和 \n。
11/05 00:09, 14F
好,我稍後再去看 shellcheck FreeBSD 燒了, 那麼到 Mac 上應該不會太好.... 沒有 \? 的話, 那先用 http[s]\{0,1\} 吧 這裡我一直覺得很心虛, 因為 httpx: 也 match!? 不知為甚麼, \{m, n\} 對我而言一直都是"失控"的... \n 的話, 那大概只能斷成兩行了, 反正, 另外設個變數 NL="\n" 來用在 sed 裡, 也一樣醜... ※ 編輯: cuello (118.167.174.150 臺灣), 11/05/2020 14:16:25 剛去裝了 shellcheck. 它對我的 A && B || C 有意見 SC2015: Note that A && B || C is not if-then-else. C may run when A is true. 請問有人,甚麼情況下碰過 A=true 但 C 卻被執行的? ※ 編輯: cuello (118.167.174.150 臺灣), 11/05/2020 14:41:56

11/05 15:30, 3年前 , 15F
B false?
11/05 15:30, 15F

11/05 15:59, 3年前 , 16F
是說,我一直相信,B false 的情況,跟 C 一樣,
11/05 15:59, 16F

11/05 15:59, 3年前 , 17F
evaluation 會停下來,return false 的值...
11/05 15:59, 17F

11/05 16:01, 3年前 , 18F
對於 Bourne shell 而言,我一直保持這種態度,
11/05 16:01, 18F

11/05 16:01, 3年前 , 19F
現在居然要被推翻了嗎? :(
11/05 16:01, 19F

11/05 16:10, 3年前 , 20F
因為答案是 false 已經得到了
11/05 16:10, 20F

11/05 16:10, 3年前 , 21F
就不繼續 evaluate C 了
11/05 16:10, 21F

11/05 16:10, 3年前 , 22F
有誰在哪個系統上,哪個 shell 會繼續做 C 嗎?
11/05 16:10, 22F

11/05 16:19, 3年前 , 23F
假設A true,但如果B為false,就會去執行C啊
11/05 16:19, 23F

11/05 16:20, 3年前 , 24F
(後方命令會印出hello) $ true && false || echo hello
11/05 16:20, 24F

11/05 17:12, 3年前 , 25F
對對對,我是錯的,頭殼壞掉了才會這樣
11/05 17:12, 25F
各位,我一直習慣性地把 A && B || C 拿來當 if-then-else, 這是很白蚩的! 不過這個介面問題先不改了, 我們先聚焦在那一行(變兩行了) sed 吧 ※ 編輯: cuello (118.167.174.150 臺灣), 11/05/2020 17:21:02 ※ 編輯: cuello (118.167.174.150 臺灣), 11/05/2020 18:06:49 另外請問大家,Mac 上面應該沒有 xsel(1) 吧 但是可能會有對應的指令, 還有要怎麼判斷是個 Mac? ※ 編輯: cuello (118.167.174.150 臺灣), 11/05/2020 22:13:37

11/06 00:16, 3年前 , 26F
沒有 xsel, uname 會得到 Darwin
11/06 00:16, 26F

11/06 00:19, 3年前 , 27F
mac 要拿剪貼簿內容可以用 pbpaste
11/06 00:19, 27F
多了 Mac 會跑, 感覺總是比較好,希望是對的

11/06 21:19, 3年前 , 28F
我覺得沒必要全部寫在同一行,你可以把 sed 分成很多
11/06 21:19, 28F

11/06 21:20, 3年前 , 29F
11/06 21:20, 29F

11/06 21:20, 3年前 , 30F
尤其是考慮到可讀性
11/06 21:20, 30F
是的,應該從善如流的,迷失的時候忽略可讀。 不過 regex 有時不大敢, 或懶得去動. ※ 編輯: cuello (59.115.149.134 臺灣), 11/06/2020 22:18:08

11/06 23:20, 3年前 , 31F
我看 freebsd 的 sed 手冊是寫支援 `\n` 的啊?
11/06 23:20, 31F

11/06 23:20, 3年前 , 32F

11/07 13:29, 3年前 , 33F
手冊上指的應該是可以用 \n 配對輸入,但不能用在輸出。
11/07 13:29, 33F

11/07 13:35, 3年前 , 34F
根據 POSIX 的說法,若要在 s 指令中輸出換行,則要使用
11/07 13:35, 34F

11/07 13:37, 3年前 , 35F
反斜線加真正的換行字元。
11/07 13:37, 35F
所以 H 插入的 \n 是可以 match 到的? 那就可以去掉囉? ※ 編輯: cuello (59.115.149.134 臺灣), 11/07/2020 17:16:07

11/07 20:09, 3年前 , 36F
推文的時候我是用 N 測試的,可以 match 到。我也試過輸
11/07 20:09, 36F

11/07 20:10, 3年前 , 37F
出換行,用 \ 加換行字元是可以輸出的。
11/07 20:10, 37F

11/08 00:12, 3年前 , 38F
是說A &&(B||!B )||C其實就行啦
11/08 00:12, 38F

11/08 00:13, 3年前 , 39F
你會以為A&&B||C可行是因為 通常BC都不會當表達式了不
11/08 00:13, 39F

11/08 00:13, 3年前 , 40F
會care $?是否為0
11/08 00:13, 40F

11/08 09:34, 3年前 , 41F
因為我B常是在做 assignment,用慣了開始錯覺吧
11/08 09:34, 41F

11/08 09:34, 3年前 , 42F
所以不要常用成語,idiom 用多了會變 idiot! :)
11/08 09:34, 42F

11/08 13:22, 3年前 , 43F
用 A && (B||true) || C會更好,避免B不是idempotent以及
11/08 13:22, 43F

11/08 13:22, 3年前 , 44F
省運算時間
11/08 13:22, 44F

11/08 15:08, 3年前 , 45F
但要用 {} ,用 () 會在子 shell 裡賦值沒有用
11/08 15:08, 45F

11/08 15:55, 3年前 , 46F
查了一下, (list) 的return value是list的值,實際用前述
11/08 15:55, 46F

11/08 15:56, 3年前 , 47F
true false命令測試也確實如此
11/08 15:56, 47F

11/08 15:57, 3年前 , 48F
true && (false||true) || echo hello 不會印hello
11/08 15:57, 48F

11/08 15:58, 3年前 , 49F
true && (false||false) || echo hello 會印hello
11/08 15:58, 49F

11/08 16:00, 3年前 , 50F
喔,我懂了,是指前面u大說的拿來assignment
11/08 16:00, 50F

11/08 16:01, 3年前 , 51F
確實一律用 {} 比較不會搞混
11/08 16:01, 51F

11/08 18:26, 3年前 , 52F
樓上大大是對的
11/08 18:26, 52F

11/09 01:19, 3年前 , 53F
推 學習了
11/09 01:19, 53F
文章代碼(AID): #1VeTyVfS (Linux)
文章代碼(AID): #1VeTyVfS (Linux)