我想透過使用文件名的一部分來選擇一系列文件,以用於複製、移動等。
隨機範例清單:
- α1a
- α2aa
- 阿爾法3abc
- 布拉沃A1
- 布拉沃B2bb
- 查理
- DeltaA1FDFD
- DeltaA2大法
- 德爾塔A2222
- δC1
- ……(一堆其他文件)
我想運行一些從 alpha2* 到 deltaA* 的命令,這將在列表中選擇 2-9。這樣我就可以根據名稱選擇一個範圍,而不用擔心實際上有多少文件,並且不會獲得額外的內容。
答案1
start=alpha2*
end=deltaA*
for file in *
do
if [[ $file > $start && ( $file < $end || $file == $end ) ]]; then
echo $file
fi
done
您可以將檔案儲存在陣列中,而不是 echo:
array+=($file)
然後使用陣列來複製、移動檔案...或簡單地在 for 迴圈中執行命令。
答案2
Shell 程式設計不太擅長字典順序比較。在 bash、ksh 或 zsh 中,您可以使用<
條件運算符比較兩個字串(POSIX sh 僅具有數字比較)。
run_in_range () {
start_at="$1"; end_before="$2"; command="$3"; shift 3
for item do
if [[ ! ($x < $start_at) && ($x < $end_before) ]]; then
"$command" "$item"
fi
done
}
run_in_range alpha2 deltaB some_command *
請注意,我使用第一個排除的項目作為第二個參數:deltaB
是所有以 開頭的字串之後的最小字串deltaA
。如果你想deltaA
作為參數傳遞,你可以這樣做。
run_in_inclusive_range () {
start_at="$1"; end_on_prefix="$2"; command="$3"; shift 3
for item do
if [[ ! ($x < $start_at) && ($x < $end_on_prefix || $x == "$end_on_prefix"*) ]]; then
"$command" "$item"
fi
done
}
run_in_inclusive_range alpha2 deltaA some_command *
此程式碼不依賴通配符的順序:即使項目清單未排序,它也可以運作。這使得程式碼更加健壯,但速度稍慢,因為它必須遍歷整個清單。
這是一種僅依賴 POSIX 功能的替代方法。它用於sort
進行字串比較。這假設項目中沒有換行符號。此函數恢復 和 globbing 的預設值IFS
(恢復環境設定是可能的,但令人煩惱的是很難)。
run_in_range () {
IFS='
'; set -f
start_at="$1"; end_before="$2"; command="$3"; shift 3
set $({
printf '%s1\n' "$@"
printf '%s0\n' "$start_at" "$end_before"
} | sort | sed '/0$/,/0$/ s/1$//p')
unset IFS; set +f
for item do
"$command" "$item"
done
}
解釋:
- 建立一個包含附加項目
1
和附加邊界的清單0
。 - 對清單進行排序。
- 列印兩條邊界線之間的線(以 結尾的線
0
),但僅列印以 結尾的線1
(即項目),且不帶尾隨1
。
答案3
在我看來,這個問題比看起來更容易解決:
假設有一種方法可以取得列表,每行一個文件。
對於目前目錄:
list="$(printf '%s\n' *)"
只需將限製附加到列表中並對其進行排序:
nl='
'
lim1="alpha2"
lim2="deltaA"
echo -- "$list""$nl""$lim1""$nl""$lim2" | sort
然後開始在 lim1 上列印(注意 lim1 和 lim2 與現有文件名不符)並在 lim2 上停止。
另外,為了簡單起見,請選擇要列印的檔案之前的最短字串以及需要選擇的最後一個檔案之後排序的最短字串。
有用的是排他列表(不包括限制的列表),
但提供了兩個解決方案。
基本價值觀:
list="$(printf '%s\n' *)"
lim1=alpha2
lim2=deltaA
使用 awk 獲得包含清單的解決方案:
echo "awk----------------inclusive"
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
awk -v lim1="$lim1" -v lim2="$lim2" '$0==lim1,$0==lim2{print}'
使用 awk 取得獨佔清單的解決方案:
echo "awk----------------exclusive"
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
awk -v lim1="$lim1" -v lim2="$lim2" '$0==lim1{p=1;next};$0==lim2{p=0};p'
包含清單的 shell 解決方案:
echo "shell---------------inclusive"
show=0
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
while IFS="$nl" read -r line; do
[ "$line" = "$lim1" ] && show=1
[ "$show" = "1" ] && printf '%s\n' "$line"
[ "$line" = "$lim2" ] && show=0
done
以及外殼的獨家解決方案:
show=0
echo "$list""$nl""$lim1""$nl""$lim2" | sort |
while read -r line; do
[ "$line" = "$lim2" ] && show=0
[ "$show" = "1" ] && printf '%s\n' "$line"
[ "$line" = "$lim1" ] && show=1
done