Path

將路徑規範分解為最長公共前綴 + 後綴

  • March 18, 2021

給定任意兩個絕對 Unix 路徑規範1,可以將每個規範分解為最長公共前綴和特定後綴的串聯。例如,

/abc/bcd/cdf     -> /abc/bcd + cdf
/abc/bcd/chi/hij -> /abc/bcd + chi/hij

是否有 Unix 實用程序(或實用程序)來計算這種分解?(我添加了“或實用程序”,以防有單獨的實用程序用於計算最長公共前綴和計算相對路徑。)

(我意識到編寫這樣的實用程序並不是非常困難,但我盡量優先考慮那些或多或少標準的工具,而不是定制的工具。)

1我寫“路徑規範”而不是“路徑”來迴避諸如給定文件系統中存在(路徑)、連結等問題。

您可以在 shell 循環中執行此操作。下面的程式碼應該適用於各種帶有額外斜杠的奇怪路徑;如果你所有的路徑都是這種形式/foo/bar,你可以用更簡單的東西逃脫。

split_common_prefix () {
 path1=$1
 path2=$2
 common_prefix=
 ## Handle initial // specially
 case $path1 in
   //[!/]*) case $path2 in
              //[!/]*) common_prefix=/ path1=${path1#/} path2=${path2#/};;
              *) return;;
            esac;;
   /*) case $path2 in
         /*) :;;
         *) return;;
       esac;;
   *) case $path2 in /*) return;; esac;;
 esac
 ## Normalize multiple slashes
 trailing_slash1= trailing_slash2=
 case $path1 in */) trailing_slash1=/;; esac
 case $path2 in */) trailing_slash2=/;; esac
 path1=$(printf %s/ "$path1" | tr -s / /)
 path2=$(printf %s/ "$path2" | tr -s / /)
 if [ -z "$trailing_slash1" ]; then path1=${path1%/}; fi
 if [ -z "$trailing_slash2" ]; then path2=${path2%/}; fi
 ## Handle the complete prefix case (faster, necessary for equality and
 ## for some cases with trailing slashes)
 case $path1 in
   "$path2")
     common_prefix=$path1; path1= path2=
     return;;
   "$path2"/*)
     common_prefix=$path2; path1=${path1#$common_prefix} path2=
     return;;
 esac
 case $path2 in
   "$path1"/*)
     common_prefix=$path1; path1= path2=${path2#$common_prefix}
     return;;
 esac
 ## Handle the generic case
 while prefix1=${path1%%/*} prefix2=${path2%%/*}
       [ "$prefix1" = "$prefix2" ]
 do
   common_prefix=$common_prefix$prefix1/
   path1=${path1#$prefix1/} path2=${path2#$prefix1/}
 done
}

或者,確定兩個字元串中最長的公共前綴並將其修剪到最後一個/字元(公共前綴僅由斜杠組成時除外)。

您可以使用以下方法計算行列表的最長公共前導子字元串:

sed -e '1{h;d;}' -e 'G;s,\(.*\).*\n\1.*,\1,;h;$!d'

例如:

/abc/bcd/cdf
/abc/bcd/cdf/foo
/abc/bcd/chi/hij
/abc/bcd/cdd

返回:

/abc/bcd/c

要將其限制為路徑組件:

sed -e 's,$,/,;1{h;d;}' -e 'G;s,\(.*/\).*\n\1.*,\1,;h;$!d;s,/$,,'

(返回/abc/bcd上面的範例)。

引用自:https://unix.stackexchange.com/questions/67078