这是对问题Y的回答(忽略问题X),受OP的尝试启发:
#!/bin/bash
LC_COLLATE=C
while read ls_out
do
extra=0
perms=0
for i in {1..9}
do
# Shift $perms to the left one bit, so we can always just add the LSB.
let $((perms*=2))
this_char=${ls_out:i:1}
# If it's different from its upper case equivalent,
# it's a lower case letter, so the bit is set.
# Unless it's "l" (lower case L), which is special.
if [ "$this_char" != "${this_char^}" ] && [ "$this_char" != "l" ]
then
let $((perms++))
fi
# If it's not "r", "w", "x", or "-", it indicates that
# one of the high-order (S/s=4000, S/s/L/l=2000, or T/t=1000) bits
# is set.
case "$this_char" in
([^rwx-])
let $((extra += 2 ** (3-i/3) ))
esac
done
printf "%o%.3o\n" "$extra" "$perms"
done
上面包含了一些bashisms。以下版本似乎符合POSIX:
#!/bin/sh
LC_COLLATE=C
while read ls_out
do
extra=0
perms=0
for i in $(seq 1 9)
do
# Shift $perms to the left one bit, so we can always just add the LSB.
: $((perms*=2))
this_char=$(expr "$ls_out" : ".\{$i\}\(.\)")
# Lower case letters other than "l" indicate that permission bits are set.
# If it's not "r", "w", "x", or "-", it indicates that
case "$this_char" in
(l)
;;
([a-z])
: $((perms+=1))
esac
# If it's not "r", "w", "x", or "-", it indicates that
# one of the high-order (S/s=4000, S/s/L/l=2000, or T/t=1000) bits
# is set.
case "$this_char" in
([!rwx-])
: $((extra += 1 << (3-i/3) ))
esac
done
printf "%o%.3o\n" "$extra" "$perms"
done
笔记:
- 该
LC_COLLATE=C
告诉shell将字母序列范围的模式与使用ASCII顺序,因此[a-e]
相当于[abcde]
。在某些语言环境中(例如en_US),[a-e]
它等效于[aAbBcCdDeE]
(即[abcdeABCDE]
),或者[abcdeABCD]
-请参见为什么bash case语句不区分大小写...?)
在第二个版本(与POSIX兼容的版本)中:
第一条case
语句可以重写:
case "$this_char" in
([a-km-z])
: $((perms+=1))
esac
但是我认为我现在所拥有的方式使人们更容易看出来l
这封信的处理方式有所不同。或者,可以将其重写:
case "$this_char" in
([rwxst])
: $((perms+=1))
esac
因为r
,w
,x
,s
,和t
都应该永远出现在模式字符串(除了那唯一的字母l
)。
第二条case
语句可以重写:
case "$this_char" in
([rwx])
;;
([A-Za-z])
: $((extra += 1 << (3-i/3) ))
esac
强制执行仅字母对指定模式位有效的规则。(相比之下,完整脚本中更简洁的版本是惰性的,将接受-rw@rw#rw%
等效于 rwSrwSrwT
。)或者,可以将其重写:
case "$this_char" in
([SsTtLl])
: $((extra += 1 << (3-i/3) ))
esac
因为S
,s
,T
,t
,L
,和l
都应该永远出现在模式字符串,唯一的字母(除r
,w
和x
)。
用法:
$ echo drwxr-xr-x | chmod-format
0755
$ echo -rwsr-sr-x | chmod-format
6755
$ echo -rwSr-Sr-- | chmod-format
6644
$ echo -rw-r-lr-- | chmod-format
2644
$ echo ---------- | chmod-format
0000
而且,是的,我知道最好不要使用echo
可能以-
; 开头的文本;我只是想复制问题中的用法示例。注意,显然,它忽略了第0个字符(即前导d
/ b
/ c
/ -
/ l
/ p
/ s
/ / D
)和第10个字符(+
/ .
/ @
)。假设的维护者ls
永远不会在第三个,第六个或第九个位置将r
/ R
或w
/ 定义
W
为有效字符(并且,如果确实如此,则应使用木棍将其打败)。
另外,我刚刚在如何恢复/ var下所有文件的默认组/用户所有权下
通过cas找到了以下代码:
let perms=0
[[ "${string}" = ?r???????? ]] && perms=$(( perms + 400 ))
[[ "${string}" = ??w??????? ]] && perms=$(( perms + 200 ))
[[ "${string}" = ???x?????? ]] && perms=$(( perms + 100 ))
[[ "${string}" = ???s?????? ]] && perms=$(( perms + 4100 ))
[[ "${string}" = ???S?????? ]] && perms=$(( perms + 4000 ))
[[ "${string}" = ????r????? ]] && perms=$(( perms + 40 ))
[[ "${string}" = ?????w???? ]] && perms=$(( perms + 20 ))
[[ "${string}" = ??????x??? ]] && perms=$(( perms + 10 ))
[[ "${string}" = ??????s??? ]] && perms=$(( perms + 2010 ))
[[ "${string}" = ??????S??? ]] && perms=$(( perms + 2000 ))
[[ "${string}" = ???????r?? ]] && perms=$(( perms + 4 ))
[[ "${string}" = ????????w? ]] && perms=$(( perms + 2 ))
[[ "${string}" = ?????????x ]] && perms=$(( perms + 1 ))
[[ "${string}" = ?????????t ]] && perms=$(( perms + 1001 ))
[[ "${string}" = ?????????T ]] && perms=$(( perms + 1000 ))
我已经测试了此代码(但没有彻底地测试过),它似乎可以工作,除了它不能识别l
或排L
在第六位。但是请注意,尽管此答案在简洁性和清晰度方面是优越的,但我的却实际上更短(仅计算循环内的代码;处理单个-rwxrwxrwx
字符串的代码,不计算注释),并且它甚至可以变得更短通过更换
用。if condition; then …
condition && …
当然,您不应该解析的输出ls
。
stat
。你有吗?(这是一个GNU工具,因此大多数在Linux上可用,而在Unix上则不可用。)