我有一个主要是版本号的目录,我正在尝试确定在另一个特定版本之前进行版本排序的目录。
这里的背景,由于担心这会导致XY问题,这些版本号是从Web内容的git标签派生的,我们将网站虚拟主机的public_html
目录符号链接到版本化目录。 / p>
它看起来像这样:
drwxr-xr-x 8 graham www 17 Oct 17 2013 v2.0.10
drwxr-xr-x 8 graham www 17 Oct 17 2013 v2.0.11
drwxrwxr-x 8 graham www 17 Aug 29 2013 v2.0.8
drwxr-xr-x 8 brian www 17 Oct 17 2013 v2.0.9
...
drwxr-xr-x 9 graham www 21 Aug 5 2015 v4.19.0
drwxr-xr-x 10 graham www 19 Dec 17 2014 v4.2.0
drwxr-xr-x 9 brian www 21 Aug 10 2015 v4.20.0
drwxr-xr-x 9 brian www 21 Aug 10 2015 v4.20.0-fail
drwxr-xr-x 9 graham www 21 Aug 11 2015 v4.20.1
...
drwxr-xr-x 9 graham www 19 Mar 14 11:00 v4.35.0
drwxr-xr-x 9 graham www 19 Mar 14 13:28 v4.36.0
drwxr-xr-x 9 graham www 19 Mar 16 10:58 v4.36.1
lrwxr-xr-x 1 graham www 11 Mar 16 11:13 public_html -> v4.36.1
符号链接可能并不总是指向最新版本(例如,如果我们不得不退出更改)。我的目标是找到正确命名的目录(即我们跳过*-fail
等),该目录在public_html
指向的版本之前排序。
我在FreeBSD中,所以我的stat
命令可以很好地运行:
read target <<<"$(stat -f'%Y' "${base}/public_html")"
如果您使用Linux,我认为您可以通过以下方式获得相同的效果:
target="$(stat -c '%N' "${base}/public_html")"
target="${target#* -> ?}"; target="${target%?}"
但是从这里开始,我不确定如何收集版本号。请注意,我在FreeBSD中,因此我的sort
命令没有-V
选项。我尝试了两种方法。
第一种是在目录内容上处理while循环:
shopt -s extglob
while read this; do
[[ "$this" = "$target" ]] && break
previous="$this"
done < $(ls -1d v+([0-9]).+([0-9]).+([0-9]) | sort -n -t . -k1,1 -k2,2 -k3,3)
第二个非常相似,而是解析数组:
shopt -s extglob
a=( $(ls -1d v+([0-9]).+([0-9]).+([0-9]) | sort -n -t . -k1,1 -k2,2 -k3,3) )
for (( n=0; n<${#a[@]}; n++ )); do
[[ "${a[$n]}" = "$target" ]] && break
previous="${a[$n]}"
done
其中两个都是sort
,其中第一个字段似乎没有排序。我怀疑是因为它不是数字(开头是“v”,用“。”分隔)。有没有办法可以指定多个分隔符,或以某种方式“忽略”v
?
或者有没有比使用外部sort
命令更好的方法来处理这个问题,该命令具有非便携式选项?也许是bash内在的东西?
感谢。
答案 0 :(得分:0)
也许不是完整的解决方案,但您可以通过以下方式逃脱:
public class ConnectedFragment extends Fragment {
private StateModifier stateModifier;
private IpAddressChangedListener ipAddressChangedListener;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.connected_fragment_layout, container, false);
root.findViewById(R.id.remote_control_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stateModifier.remoteControl();
}
});
root.findViewById(R.id.sounds_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stateModifier.soundsControl();
}
});
final EditText editText = (EditText)root.findViewById(R.id.ip_edit_text);
root.findViewById(R.id.change_ip_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ipAddressChangedListener.onIpChangedListener(editText.getText().toString());
}
});
return root;
}
public void setStateModifier(StateModifier stateModifier) {
this.stateModifier = stateModifier;
}
public void setIpAddressChangedListener(IpAddressChangedListener ipAddressChangedListener) {
this.ipAddressChangedListener = ipAddressChangedListener;
}
}
这里的区别在于,数字字段的ls -1d v+([0-9]).+([0-9]).+([0-9]) | sort -t . -k1,1 -k2,2n -k3,3n
仅应用于第二个和第三个字段,因此您将在第一个字段上按字母顺序继续排序。
这对您从-n
跳转到v9.x.x
没有帮助,但是当您在不到三年的时间内从v10.x.x
转到v2
时,也许它“足够好”。
ALSO:
v4
之类的内容确定最新的主要版本号,然后后续排序基于major=$(ls -1d v[0-9]* | tail -1); major=${major%%.*}"
。然后,您可以安全地对数字字段进行排序。答案 1 :(得分:0)
您可以分隔字母前缀,按子字段数字排序,然后合并
$ ls -1 v* | sed 's/^v/v./' | sort -t. -k2,2n -k3,3n -k4n | sed 's/^v\./v/'
v2.0.8
v2.0.9
v2.0.10
v2.0.11
v4.2.0
v4.19.0
v4.20.0
v4.20.0-fail
v4.20.1
v4.26.1
v4.35.0
v4.36.0
v10.0.1
请注意,我添加了v10。*来验证它是未来的证明。
答案 2 :(得分:0)
这个纯粹的Bash(readlink
除外)解决方案进行线性搜索而不是排序:
VERSION_RX='^v([0-9][0-9]*)\.([0-9][0-9]*)\.([0-9][0-9]*)$'
target=$(readlink "$base/public_html")
# target == v1.22.333 -> target_key == 000000001_000000022_000000333
[[ $target =~ $VERSION_RX ]] || exit 1
printf -v target_key '%09d_%09d_%09d' \
"${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
pred_dir=
pred_key=
for path in "$base"/v*.*.* ; do
dir=${path##*/}
[[ $dir == "$target" ]] && continue
[[ $dir =~ $VERSION_RX ]] || continue
printf -v key '%09d_%09d_%09d' \
"${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
[[ $key > $target_key ]] && continue
if [[ -z $pred_key || $key > $pred_key ]] ; then
pred_dir=$dir
pred_key=$key
fi
done
echo "$pred_dir"