basename命令和dirname命令

basename:从文件名中去掉路径信息, 只打印出文件名. 结构 basename $0 可以让脚本知道它自己的名字

可以用来显示用法信息, 比如如果你调用脚本的时候缺少参数, 可以使用如下语句:
echo "Usage: basename $0 arg1 arg2 ... argn"

$0:显示会包括当前脚本或命令的路径

dirname:从带路径的文件名中去掉文件名, 只打印出路径信息

basename 和 dirname 可以操作任意字符串. 参数可以不是一个真正存在的文件, 甚至可以不是一个文件名

cd dirname $0 和PWD用法

在命令行状态下单纯执行 $ cd dirname $0 是毫无意义的。因为他返回当前路径的"."。 这个命令写在脚本文件里才有作用,他返回这个脚本文件放置的目录,并可以根据这个目录来定位所要运行程序的相对位置(绝对位置除外)。 在/home/admin/test/下新建test.sh内容如下:

cd `dirname $0`
echo `pwd`

然后返回到/home/admin/执行:bash test/test.sh 运行结果: /home/admin/test

这样就可以知道一些和脚本一起部署的文件的位置了,只要知道相对位置就可以根据这个目录来定位,而可以不用关心绝对位置。这样脚本的可移植性就提高了,扔到任何一台服务器,(如果是部署脚本)都可以执行。

bash or zsh 添加环境变量PATH

bash:.bashrc zsh:.zshrc

在最后一行添加以下命令,其中:表示路径分隔符,~/bin就是我们刚才创建的文件路径 export PATH=$PATH:~/bin

这样的话,在~/bin添加一些脚本,就可以直接在别的路径通过名字执行了

Bash shell脚本打印出正在执行的命令

默认情况下,bash脚本不会打印执行的每个命令,这个有时候不太方面。

如下的方法可以让bash脚本打印出执行的命令:

1、在脚本里添加

set -v

或者 #!/bin/bash -v

以加 set -v 最好。

set -v 和 set -o verbose 是一样的

2、添加

set -x

或者 #!/bin/bash -x

3、 bash -v script.sh 或者 bash -x script.sh

Bash Shell中Shift用法

shift可以用来向左移动位置参数。
Shell的名字 $0
第一个参数 $1
第二个参数 $2
第n个参数 $n
所有参数 $@ 或 $*
参数个数 $#

shift默认是shift 1

例:


#----------------------------输出文字-开始---------------------------- #!/bin/bash #Filename: shift.sh 
#by www.jbxue.com
until [ -z "$1" ] # Until all parameters used up
do
echo "$@ " shift done
#----------------------------输出文字-结束----------------------------
 sh shift.sh 1 2 3 4 5 6 7 8 9
#----------------------------输出文字-开始----------------------------
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9
4 5 6 7 8 9
5 6 7 8 9
6 7 8 9
7 8 9
8 9
9
#----------------------------输出文字-结束----------------------------

shift 命令:可以使脚本的所有参数位置向左移动一位(删除第一位,第二个参数变成了第一个,以此类推)

因为shell脚本最多定位九个变量,所以需要 shift 来获取超出9个之外的 参数

#! bin/bash
func()
{
 #通过while和shift命令一次获取参数值
 while (($# > 0))
 do
  echo "$1"
  shift
 done
}
func 1 2 3 4 5 6 7 8 9 0

shift 命令会影响到系统变量 $# 的值

shell 文件路径

假设我们定义了一个变量为:

file=/dir1/dir2/dir3/my.file.txt

可以用${ }分别替换得到不同的值:

${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:删掉最后一个 /  及其左边的字符串:my.file.txt
${file#*.}:删掉第一个 .  及其左边的字符串:file.txt
${file##*.}:删掉最后一个 .  及其左边的字符串:txt
${file%/*}:删掉最后一个  /  及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:删掉第一个 /  及其右边的字符串:(空值)
${file%.*}:删掉最后一个  .  及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:删掉第一个  .   及其右边的字符串:/dir1/dir2/dir3/my
${file:0:5}:提取最左边的 5 个字节:/dir1  
${file:5:5}:提取第 5 个字节右边的连续5个字节:/dir2

记忆的方法为:

# 是去掉左边(键盘上#在 $ 的左边)  
% 是去掉右边(键盘上% 在$ 的右边)  
单一符号是最小匹配;两个符号是最大匹配  

也可以对变量值里的字符串作替换:

${file/dir/path}:将第一个dir 替换为path:/path1/dir2/dir3/my.file.txt  
${file//dir/path}:将全部dir 替换为 path:/path1/path2/path3/my.file.txt

利用 ${ } 还可针对不同的变数状态赋值(沒设定、空值、非空值): ${file-my.file.txt} :假如 $file 沒有设定,則使用 my.file.txt 作传回值。(空值及非空值時不作处理) ${file:-my.file.txt} :假如 $file 沒有設定或為空值,則使用 my.file.txt 作傳回值。 (非空值時不作处理) ${file+my.file.txt} :假如 $file 設為空值或非空值,均使用 my.file.txt 作傳回值。(沒設定時不作处理) ${file:+my.file.txt} :若 $file 為非空值,則使用 my.file.txt 作傳回值。 (沒設定及空值時不作处理) ${file=my.file.txt} :若 $file 沒設定,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (空值及非空值時不作处理) ${file:=my.file.txt} :若 $file 沒設定或為空值,則使用 my.file.txt 作傳回值,同時將 $file 賦值為my.file.txt 。 (非空值時不作处理) ${file?my.file.txt} :若 $file 沒設定,則將 my.file.txt 輸出至 STDERR。 (空值及非空值時不作处理)

${file:?my.file.txt} :若 $file 没设定或为空值,则将 my.file.txt 输出至 STDERR。 (非空值時不作处理) ${#var} 可计算出变量值的长度:

${#file} 可得到 27 ,因为/dir1/dir2/dir3/my.file.txt 是27个字节

shell产生随机数七种方法

https://blog.csdn.net/taiyang1987912/article/details/39997303

方法1:系统环境变量

echo $RANDOM

生成0-32767之间的整数随机数,若超过5位可以加个固定10位整数,然后进行求余。 生成400000~500000的随机数:

    #!/bin/bash  
      
    function rand(){  
        min=$1  
        max=$(($2-$min+1))  
        num=$(($RANDOM+1000000000)) #增加一个10位的数再求余  
        echo $(($num%$max+$min))  
    }  
      
    rnd=$(rand 400000 500000)  
    echo $rnd  
      
    exit 0  

方法2:使用awk的随机函数

csh没有$RANDOM,awk刚好能用

 awk 'BEGIN{srand();print rand()*1000000}'    #可以加上if判断,779644

方法3:openssl rand产生随机数

openssl rand 用于产生指定长度个bytes的随机字符。-base64或-hex对随机字符串进行base64编码或用hex格式显示。

openssl rand -base64 8 | md5sum | cut -c1-8    #八位字母和数字的组合,3a61800e

openssl rand -base64 8 | cksum | cut -c1-8       #八位数字,10784736

方法4:通过时间获得随机数(date)

date +%s%N       #生成19位数字,1287764807051101270

date +%s%N | cut -c6-13   #取八位数字,21793709

date +%s%N | md5sum | head -c 8   #八位字母和数字的组合,87022fda

生成1~50的随机数:

    #!/bin/bash  
      
    function rand(){  
        min=$1  
        max=$(($2-$min+1))  
        num=$(date +%s%N)  
        echo $(($num%$max+$min))  
    }  
      
    rnd=$(rand 1 50)  
    echo $rnd  
      
    exit 0
 

方法5:通过系统内唯一数据生成随机数(/dev/random及/dev/urandom)

/dev/random存储系统当前运行的环境的实时数据,可以看作系统某时候的唯一值数据,提供优质随机数。

/dev/urandom是非阻塞的随机数产生器,读取时不会产生阻塞,速度更快、安全性较差的随机数发生器。

cat /dev/urandom | head -n 10 | md5sum | head -c 10     #32f1e953ac

cat /dev/urandom | strings -n 8 | head -n 1      #生成全字符的随机字符串,08?WU$ZU

cat /dev/urandom | sed -e 's/[^a-zA-Z0-9]//g' | strings -n 8 | head -n 1   #生成数字加字母的随机字符串,Ql2q9CXS

其中 strings -n设置字符串的字符数,head -n设置输出的行数。

head-200/dev/urandom| cksum |cut-d" " -f1   #urandom的数据很多使用cat会比较慢,在此使用head读200行,cksum将读取文件内容生成唯一的表示整型数据,cut以” “分割然后得到分割的第一个字段数据

在UNIX操作系统(包括类UNIX系统)中,/dev/random 是一个特殊的设备文件,可以用作随机数发生器或伪随机数发生器。

/dev/urandom 是 /dev/random 一个副本,非阻塞的随机数发生器,它会重复使用熵池中的数据以产生伪随机数据。这表示对 /dev/urandom 的读取操作不会产生阻塞,但其输出的熵可能小于 /dev/random 的。它可以作为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。

常用的生成随机数的方法

tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs  

该命令生成 32 位的带有 A-Za-z0-9_!@#$%^&*()-+= 的随机数,在 MacOS 中需要指定语言环境为 C 语言才行

LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs

方法6:读取linux的uuid码

UUID码全称是通用唯一识别码 (Universally Unique Identifier, UUID),UUID格式是:包含32个16进制数字,以“-”连接号分为五段,形式为8-4-4-4-12的32个字符。linux的uuid码也是有内核提供的,在/proc/sys/kernel/random/uuid这个文件内。cat/proc/sys/kernel/random/uuid每次获取到的数据都会不同。

cat /proc/sys/kernel/random/uuid| cksum | cut -f1 -d" "    #获取不同的随机整数,1675034933

cat /proc/sys/kernel/random/uuid| md5sum | cut -c1-8    #数字加字母的随机数,d69a7ebf

使用linux uuid 生成100~500随机数:

    #!/bin/bash  
      
    function rand(){  
        min=$1  
        max=$(($2-$min+1))  
        num=$(cat /proc/sys/kernel/random/uuid | cksum | awk -F ' ' '{print $1}')  
        echo $(($num%$max+$min))  
    }  
      
    rnd=$(rand 100 500)  
    echo $rnd  
      
    exit 0  
 

方法7:从元素池中随机抽取取

pool=(a b c d e f g h i j k l m n o p q r s t 1 2 3 4 5 6 7 8 9 10)

num=${#pool[*]}

result=${pool[$((RANDOM%num))]}

用于生成一段特定长度的有数字和字母组成的字符串,字符串中元素来自自定义的池子。

#!/bin/bash
length=8
i=1
 
seq=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
 
num_seq=${#seq[@]}
 
while [ "$i" -le "$length" ]
do
 seqrand[$i]=${seq[$((RANDOM%num_seq))]}
 let "i=i+1"
done
 
echo "The random string is:"
for j in ${seqrand[@]}
do
 echo -n $j
done
echo

csh里生成随机数

# 通过awk
random=$(awk 'BEGIN{srand();print rand()*1000000}')
random=$(echo $random | cut -d '.' -f 1)

# 通过/dev/urandom
random=$(cat /dev/urandom | sed -e 's/[^0-9]//g' | head -n 1)
random=$(echo $random | cut -c 1-8)

shell打包加密成可执行文件

sudo apt install shc

shc -v -r -f echo1 echo1:源文件,源文件必须指定 #!/bin/bash之类的 echo1.x:目标二进制文件 echo1.x.c:过程C文件 这个工具是将shell脚本转为C语言,然后在打包成二进制文件

shc的反编译UnSHc

    github上克隆:git clone https://github.com/yanncam/UnSHc.git,文件夹lastest中有个脚本unshc.sh可以完成反编译功能。

    ./unshc.sh -h查看使用方法,笔者使用sample里面的例程测试可以。但是笔者觉得这个工具意义不大,除非知道二级制文件是使用shc来编译的,不然反编译出来也不成功。反编译UnSHc对于开发人员来说作用不大。

多条件if判断:与 或

if [[ $a == $b || $c == $d ]]; then
    echo OR
fi
 
if [[ $a == $b && $c == $d ]]; then
    echo AND
fi

shell脚本中使用sudo免输密码

方法一:

在shell脚本中需要用root用的来执行指令: sudo 自动输入密码

echo "password" | sudo -S netstat -tlnp

参数 -S:The -S (stdin) option causes sudo to read the password from the standard input instead of the terminal device.

方法二:

  1. 打开sudo的配置文件:vim /etc/sudoers
  2. 在root ALL下行加入:username ALL=(ALL) NOPASSWD: ALL

Shell判断字符串包含关系的几种方法

   Shell中判断字符串包含关系的方法:
   1、通过grep来判断:

str1="abcdefgh"
str2="def"
result=$(echo $str1 | grep "${str2}")
if [[ "$result" != "" ]]
then
    echo "包含"
else
    echo "不包含"
fi

 2、字符串运算符

str1="abcdefgh"
str2="def"
if [[ $str1 =~ $str2 ]]
then
    echo "包含"
else
    echo "不包含"
fi

3、利用通配符

str1="abcdefgh"
str2="def"
if [[ $str1 == *$str2* ]]
then
    echo "包含"
else
    echo "不包含"
fi

 4、利用case in 语句

str1="abcdefgh"
str2="def"
case $str1 in 
    *"$str2"*) echo Enemy Spot ;;
    *) echo nope ;;
esa

 5、利用替换

str1="abcdefgh"
str2="def"
if [[ ${str1/${str2}//} == $str1 ]]
    then
       echo "不包含"
    else
      echo "包含"
fi

if判断时防止参数为空

if[x$1 = x];
当$1为a时
if[x$1 = x]; 实际就会判断 xa = x
这样写的主要目的是当如果写成["$1" = "$2" ] 
在 $1,$2为空时会在某些bash版本中出现编译错误所以运用了shell中的字符抵消原则。

文件名带空格

  1. 使用双引号括起来,模糊匹配时可以"*\ *"
  2. 修改IFS,不用空格作为IFS
  3. 在处理文件名之前,先将空格处理为其它字符,比如_

重定向到文件时,发生导致“模糊重定向”消息

ambiguous redirect的叫法有: + 模糊重定向 + 歧义重定向

echo $AAAA" "$DDDD" "$MOL_TAG >> ${OUPUT_RESULTS}

上面的写法可能会报错:${OUPUT_RESULTS}: ambiguous redirect。如果OUPUT_RESULTS碰巧有空格,j就会出现“歧义重定向”。 解决办法是:用引号括起你的变量。

$ var="file with spaces" 
$ echo $AAAA" "$DDDD" "$MOL_TAG >> ${var} 
bash: ${var}: ambiguous redirect 
$ echo $AAAA" "$DDDD" "$MOL_TAG >> "${var}" 
$ cat file\ with\ spaces
aaaa dddd mol_tag

重定向文件名称中的空格会导致“歧义重定向”消息。 例如,如果您重定向到application$(date +%Y%m%d%k%M%S).log并指定了错误的格式字符,则重定向将在上午10点之前失败。但是,如果您使用application$(date +%Y%m%d%H%M%S).log,它将会成功。这是因为%k格式生成上午9点的' 9',而%H生成上午9点的'09'

echo $(date +%Y%m%d%k%M%S)给了20140626 95138

echo $(date +%Y%m%d%H%M%S)给了20140626095138

错误的日期可能如下所示:

echo "a" > myapp20140626 95138.log

其中,以下是所需的:

echo "a" > myapp20140626095138.log

另一件可能导致“二义性重定向”的事情是您正在编写的变量名中的\t \n \r

也许不是\n\r?但在谨慎方面犯了错误

尝尝这个

echo "a" > ${output_name//[$'\t\n\r']}

我在分析HTML \t时遇到了这个问题。

原文:https://cloud.tencent.com/developer/ask/sof/69279

shell脚本中使用sudo免输密码

方法一:

在shell脚本中需要用root用的来执行指令: sudo 自动输入密码

echo "password" | sudo -S netstat -tlnp

参数 -S:The -S (stdin) option causes sudo to read the password from the standard input instead of the terminal device.

方法二:

  1. 打开sudo的配置文件:vim /etc/sudoers
  2. 在root ALL下行加入:username ALL=(ALL) NOPASSWD: ALL