Blog

比较两个文件的新旧

Content #

-nt测试会判定一个文件是否比另一个文件更新。如果文件较新,那意味着其文件创建日期更晚。-ot测试会判定一个文件是否比另一个文件更旧。如果文件较旧,则意味着其文件创建日期更早:

$ cat check_file_dates.sh
#!/bin/bash
# Compare two file's creation dates/times
#
if [ $HOME/Downloads/games.rpm -nt $HOME/software/games.rpm ]
then
     echo "The $HOME/Downloads/games.rpm file is newer"
     echo "than the $HOME/software/games.rpm file."
#
else
     echo "The $HOME/Downloads/games.rpm file is older"
     echo "than the $HOME/software/games.rpm file."
#
fi
$
$ ./check_file_dates.sh
The /home/christine/Downloads/games.rpm file is newer
than the /home/christine/software/games.rpm file.

在脚本中,这两种测试都不会先检查文件是否存在。这是一个问题。试试下面的测试:

$ rm $HOME/Downloads/games.rpm
$
$ ./check_file_dates.sh
The /home/christine/Downloads/games.rpm file is older
than the /home/christine/software/games.rpm file.

这个小示例展示了如果有其中一个文件不存在,那么-nt测试返回的信息就不正确。在-nt或-ot测试之前,务必确保文件存在。

...

sort命令处理大写字母的方法与test命令相反

Content #

sort命令处理大写字母的方法刚好与test命令相反:

$ cat SportsFile.txt
Soccer
soccer
$
$ sort SportsFile.txt
soccer
Soccer
$
$ cat sort_order_comparison.sh
#!/bin/bash
# Testing string sort order
#
string1=Soccer
string2=soccer
#
if [ $string1 \> $string2 ]
then
     echo "$string1 is greater than $string2"
else
     echo "$string1 is less than $string2"
fi
$
$ ./sort_order_comparison.sh
Soccer is less than soccer

在比较测试中,大写字母被认为是小于小写字母的。但sort命令正好相反。当你将同样的字符串放进文件中并用sort命令排序时,小写字母会先出现。这是由于各个命令使用了不同的排序技术。

比较测试中使用的是标准的Unicode顺序,根据每个字符的Unicode编码值来决定排序结果。sort命令使用的是系统的语言环境设置中定义的排序顺序。对于英语,语言环境设置指定了在排序顺序中小写字母出现在大写字母之前。

From #

Linux命令行与shell脚本编程大全

大于号和小于号必须转义(比较字符串)

Content #

$ cat bad_string_comparison.sh
#!/bin/bash
# Misusing string comparisons
#
string1=soccer
string2=zorbfootball
#
if [ $string1 > $string2 ]
then
     echo "$string1 is greater than $string2"
else
     echo "$string1 is less than $string2"
fi
$
$ ./bad_string_comparison.sh
soccer is greater than zorbfootball
$
$ ls z*
zorbfootball

这个脚本中只用了大于号,虽然没有出现错误,但结果不对。脚本把大于号解释成了输出重定向,因此创建了一个名为zorbfootball的文件。由于重定向顺利完成了,测试条件返回了退出状态码0,if语句便认为条件成立。

要解决这个问题,需要使用反斜线(\)正确地转义大于号:

$ cat good_string_comparison.sh
#!/bin/bash
# Properly using string comparisons
#
string1=soccer
string2=zorbfootball
#
if [ $string1 \> $string2 ]
then
echo "$string1 is greater than $string2"
else
     echo "$string1 is less than $string2"
fi
$
$ rm -i zorbfootball
rm: remove regular empty file 'zorbfootball'? y
$
$ ./good_string_comparison.sh
soccer is less than zorbfootball
$
$ ls z*
ls: cannot access 'z*': No such file or directory

字符串soccer小于zorbfootball,因为在比较的时候使用的是每个字符的 Unicode编码值。小写字母s的编码值是115,而z的编码值是122。因此,s小于z,进而,soccer小于zorbfootball。

...

在脚本中使用bc

Content #

现在你可能想问bash计算器是如何在shell脚本中处理浮点数运算的。还记得反引号吗?没错,可以用命令替换来运行bc命令,将输出赋给变量。基本格式如下:

variable=$(echo "options; expression" | bc)

第一部分的options允许你设置变量。如果需要多个变量,可以用分号来分隔它们。expression定义了要通过bc执行的数学表达式。下面是在脚本中执行此操作的示例:

$ cat test9
#!/bin/bash
var1=$(echo " scale=4; 3.44 / 5" | bc)
echo The answer is $var1

这个例子将scale变量设置为4位小数,在expression部分指定了特定的运算。运行这个脚本会产生如下输出:

The answer is .6880

如果要进行大量运算,那么最好的办法是使用内联输入重定向,它允许直接在命令行中重定向数据。在shell脚本中,可以将输出赋给一个变量:

variable=$(bc << EOF
options
statements
expressions
EOF
)

字符串EOF标识了内联重定向数据的起止。别忘了,仍然需要用命令替换符将bc 命令的输出赋给变量。

现在,可以将bash计算器涉及的各个部分放入脚本文件的不同行中。以下示例演示了如何在脚本中使用这项技术:

$ cat test12
#!/bin/bash

var1=10.46
var2=43.67
var3=33.2
var4=71

var5=$(bc << EOF
scale = 4
a1 = ( $var1 * $var2)
b1 = ($var3 * $var4)
a1 + b1
EOF
)

echo The final answer for this mess is $var5

From #

Linux命令行与shell脚本编程大全

...

使用test命令确定变量中是否为空

Content #

可以使用test命令确定变量中是否为空。这只需要一个简单的条件表达式:

$ cat test6.sh
#!/bin/bash
# testing if a variable has content
#
my_variable="Full"
#
if test $my_variable
then
     echo "The my_variable variable has content and returns a True."
     echo "The my_variable variable content is: $my_variable"
else
     echo "The my_variable variable doesn't have content,"
     echo "and returns a False."
fi
$
$ ./test6.sh
The my_variable variable has content and returns a True.
The my_variable variable content is: Full

由于变量my_variable中包含内容(Full),因此当test命令测试条件时,返回的退出状态码为0。这使得then语句块中的语句得以执行。

...

计算两个日期之间相隔的天数

Content #

我们将编写一个shell脚本来计算两个日期之间相隔的天数,允许用户以date命令能识别的任何格式来指定日期。

首先,将两个指定日期保存在变量中:

$date1="Jan 1, 2020"
$date2="May 1, 2020"

执行日期运算可不是件容易事,你需要知道哪个月份是28天,哪个月份是30天或 31天,还需要知道哪一年是闰年。不过好在可以从date命令那里寻求帮助。

date命令允许使用-d选项指定特定日期(以任意格式),然后以我们定义的其他格式输出该日期。为了执行日期运算,要利用纪元时间(epoch time)这个 Linux特性。纪元时间将时间指定为1970年1月1日午夜后的整数秒(这是一个古老的Unix标准)。因此,要获得2020年1月1日的纪元时间,可以这么做:

$date -d "Jan 1, 2020" +%s
1577854800

我们使用这种方法获得两个日期的纪元时间,然后相减,得到两个日期之间相隔的秒数。在此,将该值除以一天中的秒数(每分钟60秒、每小时60分钟、每天24 小时),以获得两个日期之间的天数差异。

使用命令替换将date命令的输出保存在变量中:

$time1=$(date -d "$date1" +%s)

一旦获得了两个日期的纪元时间,剩下的就是使用expr命令来计算差值了。

$ cat mydate.sh
#!/bin/bash
# calculate the number of days between two dates
date1="Jan 1, 2020"
date2="May 1, 2020"

time1=$(date -d "$date1" +%s)
time2=$(date -d "$date2" +%s)

diff=$(expr $time2 - $time1)
secondsinday=$(expr 24 \* 60 \* 60)
days=$(expr $diff / $secondsinday)

echo "The difference between $date2 and $date1 is $days days"

设置合适的权限并运行脚本:

...

用Vim编辑文件时发现没有修改权限

Content #

  1. 使用sudo命令:在保存文件时,在vim命令行模式下输入" :w !sudo tee % “,然后按下 Enter键并输入你的管理员密码。这将使用管理员权限保存文件。

  2. 切换到root用户:在保存文件之前,可以先切换到root用户,使用以下命令: “sudo su -”。然后再用vim编辑并保存文件。

  3. 修改文件权限:如果你有文件所在目录的写入权限,你可以使用chmod命令修改文件权限,使其可写入。在终端中输入"chmod +w 文件名”,然后再次尝试保存文件。

From #

sub:ACL

Content #

文件系统支持 #

检查文件系统是否支持:

❯ sudo tune2fs -l /dev/nvme0n1p5 | grep acl
Default mount options:    user_xattr acl

若没有acl属性,可重新挂载:

mount -o remount,acl /dev/sda1

基本操作 #

  1. 添加ACL

    setfacl -m u:gavin:rw,g:test:r acl_test
    
  2. 删除ACL 删除指定用户对文件的访问权限

    setfacl -x u:gavin: acl_test
    

    删除文件或目录的所有ACL规则

    setfacl -b acl_test
    
  3. 覆盖原有的ACL规则

    setfacl --set u::rw,g::rw,o::r,u:gavin:rwx,g:test:rx acl_test
    
  4. 为目录创建默认ACL

    setfacl -d -m g:test:r test
    

mask #

Default ACL是指对于一个目录进行Default ACL设置,并且在此目录下建立的文件都将继承此目录的ACL。 mask决定了可授予给ACL_USER, ACL_GROUP_OBJ, or ACL_GROUP的权限。 ACL_USER_OBJ The ACL_USER_OBJ entry denotes access rights for the file owner. ACL_USER ACL_USER entries denote access rights for users identified by the entry’s qualifier. ACL_GROUP_OBJ The ACL_GROUP_OBJ entry denotes access rights for the file group. ACL_GROUP ACL_GROUP entries denote access rights for groups identified by the entry’s qualifier. ACL_MASK The ACL_MASK entry denotes the maximum access rights that can be granted by entries of type ACL_USER, ACL_GROUP_OBJ, or ACL_GROUP. ACL_OTHER The ACL_OTHER entry denotes access rights for processes that do not match any other entry in the ACL. ACL条目中如果包含了ACL_USER和ACL_GROUP,那么必须要有ACL_MASK。没有ACL_USER和ACL_GROUP的情况下,ACL_MASK是可选的。 There is a correspondence between the file owner, group, and other permissions and specific ACL entries: the owner permissions correspond to the permissions of the ACL_USER_OBJ entry. If the ACL has an ACL_MASK entry, the group permissions correspond to the permissions of the ACL_MASK entry. Otherwise, if the ACL has no ACL_MASK entry, the group permissions correspond to the permissions of the ACL_GROUP_OBJ entry. The other permissions correspond to the permissions of the ACL_OTHER_OBJ entry. 除了文件所有者外,用setfacl添加的用户权限最大不会超过group的权限,group的权限会成为setfacl添加的用户的权限的mask。

...

找出所有设置了setuid位权限的文件

Content #

To check for a possible Trojan horse, examine the filesystem periodically for files with setuid permission. The following command lists these files: Listing setuid files

$ sudo find / -perm -4000 -exec ls -lh {} \; 2> /dev/null
-rwsr-xr-x 1 root root 25K Oct 19 15:52 /usr/bin/newgrp
-rwsr-xr-x 1 root root 35K Oct 19 15:52 /usr/bin/chfn
-rwsr-xr-x 1 root root 29K Oct 19 15:52 /usr/bin/chsh
-rwsr-xr-x 1 root root 38K Oct 19 15:52 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 35K Oct 19 15:52 /usr/bin/passwd
-rwsr-sr-x 1 root root 21K Dec 6 22:11 /usr/bin/X
-rwsr-xr-x 2 root root 104K Oct 9 04:39 /usr/bin/sudoedit
-rwsr-xr-x 2 root root 104K Oct 9 04:39 /usr/bin/sudo
-rwsr-sr-x 1 daemon daemon 44K Jul 20 2007 /usr/bin/at
-rwsr-xr-x 1 root root 14K Oct 16 10:33 /usr/bin/arping

From #