Blog

不同执行方式对$0的影响

Content #

# test.sh
echo $$
echo $0

第一种执行方式:

bash test.sh

15997 test.sh 第二种执行方式:

. test.sh

14642 bash

From #

特殊变量$?和$!

Content #

\(?用于获取上一个命令执行的结果或返回值。当一个命令执行完毕后,它会将一个返回值返回给调用它的父进程。通常,返回值为0表示命令执行成功,非零值表示命令执行失败或发生错误。通过\)?可以获取到这个返回值,以便在脚本中根据命令执行的结果进行不同的处理。

$!用于获取最后一个在后台运行的进程的PID。当你在后台启动一个进程时,Bash会为它分配一个唯一的PID,并将该PID保存在 $!中,以便你可以在之后的操作中使用这个PID。这对于跟踪和操作后台进程非常有用。

From #

将csv数据转换成sql insert语句

Content #

$cat test23
#!/bin/bash
# read file and create INSERT statements for MySQL

outfile='members.sql'
IFS=','
while read lname fname address city state zip
do
   cat >> $outfile << EOF
   INSERT INTO members (lname,fname,address,city,state,zip) VALUES
('$lname', '$fname', '$address', '$city', '$state', '$zip');
EOF
done < ${1}
$

脚本中出现了3处重定向操作。while循环使用read语句从数据文件中读取文本。注意在done语句中出现的重定向符号:

done < ${1}

当运行脚本test23时,$1代表第一个命令行参数,指明了待读取数据的文件。 read语句使用IFS字符解析读入的文本,这里将IFS指定为逗号。

脚本中另外两处重定向操作出现在同一条语句中:

cat >> $outfile << EOF

这条语句包含一个输出追加重定向(双大于号)和一个输入追加重定向(双小于号)。输出重定向将cat命令的输出追加到由$outfile变量指定的文件中。cat命令的输入不再取自标准输入,而是被重定向到脚本内部的数据。EOF符号标记了文件中的数据起止: INSERT INTO members (lname,fname,address,city,state,zip) VALUES (’$lname’, ‘$fname’, ‘$address’, ‘$city’, ‘$state’, ‘$zip’);

...

在tmp目录中创建临时文件

Content #

mktemp -t选项会强制mktemp命令在系统的临时目录中创建文件。在使用这个特性时,mktemp命令会返回所创建的临时文件的完整路径名,而不只是文件名:

$ mktemp -t test.XXXXXX
/tmp/test.xG3374
$ ls -al /tmp/test*
-rw------- 1 rich rich 0 2020-06-20 18:41 /tmp/test.xG3374
$

由于mktemp命令会返回临时文件的完整路径名,因此可以在文件系统的任何位置引用该临时文件

From #

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

创建本地临时文件

Content #

在默认情况下,mktemp会在本地目录中创建一个文件。在使用mktemp命令时,只需指定一个文件名模板即可。模板可以包含任意文本字符,同时在文件名末尾要加上6个X:

$ mktemp testing.XXXXXX
$ ls -al testing*
-rw-------   1 rich      rich      0 Jun 20 21:30 testing.UfIi13
$

mktemp命令会任意地将6个X替换为同等数量的字符,以保证文件名在目录中是唯一的。你可以创建多个临时文件,并确保每个文件名都不重复:

$ mktemp testing.XXXXXX
testing.1DRLuV
$ mktemp testing.XXXXXX
testing.lVBtkW
$ mktemp testing.XXXXXX
testing.PgqNKG
$ ls -l testing*
-rw-------    1 rich     rich      0 Jun 20 21:57 testing.1DRLuV
-rw-------    1 rich     rich      0 Jun 20 21:57 testing.PgqNKG
-rw-------    1 rich     rich      0 Jun 20 21:30 testing.UfIi13
-rw-------    1 rich     rich      0 Jun 20 21:57 testing.lVBtkW
$

From #

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

快速清空文件内容

Content #

可以在输入重定向中将/dev/null作为输入文件。由于/dev/null文件不含任何内容,因此程序员通常用它来快速清除现有文件中的数据,这样就不用先删除文件再重新创建了:

$ cat testfile
This is the first line.
This is the second line.
This is the third line.
$ cat /dev/null > testfile
$ cat testfile
$

文件testfile仍然还在,但现在是一个空文件。这是清除日志文件的常用方法,因为日志文件必须时刻等待应用程序操作。

或者用cp命令

cp -f /dev/null /var/log/apache2/access.log

From #

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

列出打开的文件描述符

Content #

有大量的命令行选项和参数可用于过滤lsof的输出。最常用的选项包括-p和-d,前者允许指定进程ID(PID),后者允许指定要显示的文件描述符编号(多个编号之间以逗号分隔)。

在打开了多个替代性文件描述符的脚本中,看一下使用lsof命令的结果:

$ cat test18
#!/bin/bash
# testing lsof with file descriptors

exec 3> test18file1
exec 6> test18file2
exec 7< testfile

/usr/sbin/lsof -a -p $$ -d0,1,2,3,6,7
$ ./test18
COMMAND  PID USER   FD   TYPE DEVICE SIZE   NODE NAME
test18  3594 rich    0u   CHR  136,0           2 /dev/pts/0
test18  3594 rich    1u   CHR  136,0           2 /dev/pts/0
test18  3594 rich    2u   CHR  136,0           2 /dev/pts/0
18  3594 rich    3w   REG  253,0    0 360712 /home/rich/test18file1
18  3594 rich    6w   REG  253,0    0 360715 /home/rich/test18file2
18  3594 rich    7r   REG  253,0   73 360717 /home/rich/testfile
$

这个脚本创建了3个替代性文件描述符,两个用作输出(3和6),一个用作输入(7)。在脚本运行lsof命令时,你会在输出中看到新的文件描述符。我们去掉了输出中的第一部分,这样就能看到最终的文件名了。文件名显示了文件描述符所使用文件的完整路径。每个文件都显示为REG类型,说明这些是文件系统中的常规文件。

...

关闭文件描述符

Content #

如果创建了新的输入文件描述符或输出文件描述符,那么shell会在脚本退出时自动将其关闭。然而在一些情况下,需要在脚本结束前手动关闭文件描述符。

要关闭文件描述符,只需将其重定向到特殊符号&-即可。在脚本中如下所示:

exec 3>&-

该语句会关闭文件描述符3,不再在脚本中使用。

一旦关闭了文件描述符,就不能在脚本中向其写入任何数据,否则shell会发出错误消息。

在关闭文件描述符时还要注意另一件事。如果随后你在脚本中打开了同一个输出文件,那么shell就会用一个新文件来替换已有文件。这意味着如果你输出数据,它就会覆盖已有文件。

From #

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

创建读写文件描述符

Content #

可以打开单个文件描述符兼做输入和输出,这样就能用同一个文件描述符对文件进行读和写两种操作了。

但使用这种方法时要特别小心。由于这是对一个文件进行读和写两种操作,因此 shell会维护一个内部指针,指明该文件的当前位置。任何读或写都会从文件指针上次的位置开始。如果粗心的话,这会产生一些令人瞠目的结果。来看下面这个例子:

$ cat test16
#!/bin/bash
# testing input/output file descriptor

exec 3<> testfile
read line <&3
echo "Read: $line"
echo "This is a test line" >&3
$ cat testfile
This is the first line.
This is the second line.
This is the third line.
$ ./test16
Read: This is the first line.
$ cat testfile
This is the first line.
This is a test line
ine.
This is the third line.
$

在这个例子中,exec命令将文件描述符3用于文件testfile的读和写。接下来,使用分配好的文件描述符,通过read命令读取文件中的第一行,然后将其显示在 STDOUT中。最后,使用echo语句将一行数据写入由同一个文件描述符打开的文件中。

...