我試圖將所有以“m”開頭的檔案重命名為相同的名稱,除了第一個字元(或本例中的“m”)被刪除。
我的策略是:
- 列出所有文件,其中
ls
- 過濾出我想要的,
egrep
- 在我想要的字串旁邊產生我不想要的字串,用空格分隔,
awk
例如,mfoo foo
- 送入
xargs
至mv mfoo foo
一些問題:
- 這是一個好的策略嗎?
- 什麼是更好的?
我陷入了第三步,以下是我解決這個問題的方法。
我正在以下目錄中工作:
$ find .
.
./cat
./mbar
./mbaz
./mfoo
我能夠快速得到 1-2:
$ ls | egrep '^m'
mbar
mbaz
mfoo
第3步比較困難。我曾經gsub
生成我想要的第二個字串,但我不確定如何「將其與用空格分隔的原始值黏在一起」:
$ ls | egrep '^m' | awk '{ gsub(/^./, ""); print }'
bar
baz
foo
步驟 4 對我來說很有意義,儘管我不確定如何完成第 3 步,所以我還無法完成它。以下是我認為它應該如何運作的一個例子:
$ echo mfoo foo | xargs mv
$ find .
.
./cat
./foo
./mbar
./mbaz
我想我已經很接近了,我只需要找出如何保存舊值並將其列印在 gsubed 值旁邊。我嘗試過以下小示例,但它不起作用:
$ echo mfoo | awk '
pipe quote> { old = $0 }
pipe quote> { new = gsub(/^./, "") }
pipe quote> { print $old " " $new }'
awk: illegal field $(mfoo), name "old"
input record number 1, file
source line number 4
- 如何替換
$0
但保存舊值? - 為什麼我會收到此錯誤?
答案1
這應該要處理整個操作:
for file in m*; do mv "${file}" "${file#m}"; done
在運行之前,請先檢查一下
for file in m*; do echo mv "${file}" "${file#m}"; done
這將m*
glob 用於步驟 1 和 2,然後${file#m}
(從 的開頭刪除“m” ${file}
)用於步驟 3,最後使用循環用於步驟 4。
要回答您的 AWK 問題,您可以這樣解決:
echo mfoo | awk '{ print $0, substr($0, 2) }'
AWK 變數不使用$
,僅適用於欄位;這就是您的錯誤的來源:AWK 將其理解$old
為「根據 的值編號的欄位的值old
」。如果將命令放在一個區塊中(假設它們具有相同的模式),那麼也更容易閱讀。修復你的腳本給出
echo mfoo | awk '{ old = $0; gsub(/^./, ""); print old, $0 }'
答案2
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); $0 = x " " $0 }1' | xargs -l -t mv
Posix-萊實現是透過以下-L
選項xargs
:
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); $0 = x " " $0 }1' | xargs -L 1 -t mv
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); print x, $0 }' | xargs -L 1 -t mv
基於什麼我回答對於您之前關於 的詢問xargs
,我們可以在這個例子中充分利用所學到的知識。
我稍微修改了你的awk
程式碼:它保留了原始行($0
),因為gsub
func 會破壞它。然後,我們將舊的和新的放在一起,以獲得我們想要發送到的行xargs
,然後mv
使用正確的參數呼叫以實現重命名。
答案3
更好的策略是使用rename
命令。
請注意,此命令的確切語法是特定於發行版的,請參閱man
您的特定發行版版本的頁面。例如,在 Ubuntu 上,它具有 Perl 實現rename
,您可以使用正規表示式:
rename -nono 's/^m//' m*
注意:刪除該-nono
標誌才能實際執行重新命名。