我有一個從這樣的檔案夾中讀取的文本檔案串列test:
file_list="$(ls ~/Desktop/test |
while read path; do basename "$path"; done)"
這將生成這些檔案的串列:
test_1.txt
test_2.txt
我想更改名稱中的特定字串,特別test是this這樣串列就會有這樣的檔案:
this_1.txt
this_2.txt
我想直接在file_list我不想在計算機上檔案夾中的實際檔案上執行此操作。
逐一回圈是最有效的方法嗎?
uj5u.com熱心網友回復:
逐一回圈是[對檔案名執行替換]的最有效方法嗎?
不,這也不是提取基本名稱的最有效方法。就此而言,決議 的輸出也不明智ls,盡管這是一個相對良性的情況。如果您想按摩檔案名串列,那么通過一個sed或awk行程傳遞整個串列是一種更好的方法。例如:
file_list="$(
find ~/Desktop/test -mindepth 1 -maxdepth 1 -not -name '.*' |
sed 's,^.*/,,; s,^test,this,'
)"
該find命令輸出指定目錄中非點檔案的路徑,每行一個,就像ls會做的那樣。 sed然后嘗試對每個替換進行兩次替換:第一次洗掉直到并包括最后一個/字符 ala的所有內容basename,第二次替換后者出現在行左側的開頭的位置this。test
另請注意,這種方法與您原來的方法一樣,在包含換行符的檔案名方面存在問題。包含其他空格的檔案名沒有固有的問題,但是如果任何檔案名包含空格,您將無法正確解釋結果。
uj5u.com熱心網友回復:
在這里解決: https ://unix.stackexchange.com/questions/36795/find-sed-search-and-replace
您可以使用帶有 -exec 的 find 和多個 sed 命令,用以下命令分隔;:
find . -exec sed -i '' 's/\([^/.]*\)\..*/\1/g;s?users/uname?gs://uname?g' {}
第一個 sed 命令s/\([^\.]*\)\..*/\1/g在 first 之后洗掉everyting.
第二個 sed 命令s?users/uname?gs://uname?g進行替換
決議ls輸出是不好的做法。
uj5u.com熱心網友回復:
您不需要回圈或外部命令(如basename、find和sed)。試試這個Shellcheck -clean 代碼:
#! /bin/bash -p
shopt -s nullglob
files=( ~/Desktop/test/* )
bases=( "${files[@]##*/}" )
this_list="${bases[*]//test/this}"
declare -p this_list
shopt -s nullglob當沒有檔案與模式匹配時,使 glob 擴展為空。沒有它,當沒有匹配項時,glob 會擴展為(相當于)垃圾。files=( ~/Desktop/test/* )使用目錄 ( )files中所有檔案(和目錄)的路徑填充一個名為的陣列。請注意,名稱以點 ( ) 開頭的檔案被排除在外。它們可以通過在程式中更早地運行來包含。~/Desktop/test(~/Desktop/test/test_1.txt ...).shopt -s dotglobbases=( "${files[@]##*/}" )使用陣列 ( )bases中檔案的基本名稱填充陣列。請參閱引數擴展 [Bash Hackers Wiki]了解有關它在做什么的資訊。files( test_1.txt ... )##- 如果您想
.txt按照其中一條評論的建議洗掉擴展,您可以在流程中添加一個額外的階段:stems=( "${bases[@]%.txt}" ). 在 Bash 中一次執行多個字串操作(例如##和)是不可能的。% this_list="${bases[*]//test/this}"用( )替換所有條目 in填充this_list字串。同樣,請參閱引數擴展 [Bash Hackers Wiki]了解其作業原理的詳細資訊。串列中的條目由空格分隔。問題串列中的條目由換行符分隔。您可以通過在分配之前進行設定來做到這一點。請參閱Modify IFS in bash while building and array,IFS=$'\n' 的確切含義是什么?,并且“備份” $IFS 變數是一種理智的方法嗎?. 值中的第一個字符basestestthis"this_1.txt ..."this_listIFS=$'\n'this_list=...IFS用于將陣列轉換為字串時用 . 分隔陣列元素"${arrayname[*]}"。declare -p this_listthis_list以明確的方式顯示的內容。
一般的幾點:
- 切勿
ls在程式中使用。它僅供互動使用。有時你可能會在程式中使用它而僥幸,但它最終會狠狠地咬你一口。請參閱為什么不應該決議 ls(1) 的輸出和為什么不決議 'ls' (以及要做什么)?. - 避免將檔案串列放在字串中。請改用陣列。檔案路徑可以包含字串可以包含的任何字符(兩者都不能包含NUL字符)。因此,沒有安全字符或字符組合可以安全地用于分隔字串中的任意檔案路徑。可以通過以各種方式參考檔案路徑來克服該問題,但這會帶來更多問題。
- 執行此操作的“最有效”方法取決于需要處理的檔案數量(除其他外)。此答案中的代碼在低端機器上的 Cygwin 下(通常比 Linux 慢得多)下包含 10,000 個檔案的目錄中運行 0.2 秒。這對我來說已經足夠了。不過 Bash 通常很慢,當檔案數量巨大時,作為全域擴展的一部分進行的排序可能會非常慢。如果您有數十萬個檔案,那么純 Bash 代碼可能會變得無法使用。
find和的組合sed應該能夠處理更多數量的檔案,但是 Bash 可能無論如何都難以處理產生的巨大字串(或陣列)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/439461.html
標籤:重击
上一篇:如何將YAML作為bash腳本中的文本嵌入到YAML中?
下一篇:匹配模式后拆分多行
