Shell脚本问题与解答详解

内容分享2天前发布
0 0 0

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

113、为什么执行命令

$ touch ip.txt $ [[-f ip.txt]] && echo 'file exists'

时会显示

[-f: command not found

错误,即该条件表达式为什么会失败?

该条件表达式失败是因为

[[


-f

之间缺少空格。在 Bash 中,

[[

是一个关键字,用于条件测试,它和测试选项、操作数之间需要有空格分隔,正确的写法是

[[ -f ip.txt ]]

114、为什么下面使用的条件表达式两次都显示“failed”?修改这些表达式,使第一个表达式正确显示“matched”而不是“failed”。给定变量 $f1 赋值为 ‘1234.txt’,变量 $f2 赋值为 ‘report_2.txt’,执行 $ [[ $f1 == ‘+([0-9]).txt’ ]] && echo ‘matched’ || echo ‘failed’ 结果为 failed,执行 $ [[ $f2 == ‘+([0-9]).txt’ ]] && echo ‘matched’ || echo ‘failed’ 结果也为 failed。

条件表达式两次都显示“failed”,是因为默认情况下,Bash 的扩展模式(

extglob

)未启用,而

'+([0-9]).txt'

是扩展模式下的通配符模式。

要使用扩展模式,需要先启用它。可以使用

shopt -s extglob

命令来启用扩展模式。

修改后的代码如下:


shopt -s extglob
f1='1234.txt'
f2='report_2.txt'
[[ $f1 == +([0-9]).txt ]] && echo 'matched' || echo 'failed'
[[ $f2 == +([0-9]).txt ]] && echo 'matched' || echo 'failed'

这样,第一个表达式会输出“matched”,第二个表达式会输出“failed”。

115、从给定变量内容中提取紧跟在冒号(:)后面的数字。例如,当变量 $item 的值为 ‘chocolate:50’ 时,应提取出 50;当变量 $item 的值为 ‘50 apples, fig:100, books-12’ 时,应提取出 100。

可以使用以下命令来实现:

对于

$item='chocolate:50'

,可使用

bash
echo $item | cut -d ':' -f 2


这里

-d


cut

命令指定分隔符为

:


-f 2

表示取第二段。

对于

$item='50 apples, fig:100, books-12'

,可使用

bash
echo $item | grep -oP '(?<=:)[0-9]+'


grep


-oP

选项用于只输出匹配项,并使用正则表达式

(?<=:)[0-9]+

匹配冒号后的数字。

116、修改下面的表达式,使其正确报告为 true 而非 false:$ num=12345; [[ $num > 3 ]] && echo ‘true’ || echo ‘false’

原表达式使用的是字符串比较,要进行数值比较,应将

>

改为

-gt

,修改后的表达式为:


[[ $num -gt 3 ]] && echo 'true' || echo 'false'

117、编写一个名为 array.sh 的 shell 脚本,该脚本接受用户输入的数组,接着再接受一个作为索引的输入,然后显示该索引对应的数组元素。以下是几个示例:$ bash array.sh 输入数组元素: apple banana cherry 输入数组索引: 1 索引 ‘1’ 对应的元素是: banana $ bash array.sh 输入数组元素: dragon unicorn centaur 输入数组索引: -1 索引 ‘-1’ 对应的元素是: centaur


#!/bin/bash
read -p 'enter array elements: ' -a arr
read -p 'enter array index: ' idx
echo "element at index '$idx' is: ${arr[$idx]}"

118、编写一个名为 case.sh 的 shell 脚本,该脚本精确接受两个命令行参数。第一个参数可以是 lower、upper 或 swap,用于转换第二个参数的内容。以下展示了脚本的调用示例,包括命令行参数不符合脚本预期时的处理情况。如:$ ./case.sh upper ‘how are you?’ 输出 HOW ARE YOU?;$ ./case.sh lower PineAPPLE 输出 pineapple;$ ./case.sh swap ‘HeLlo WoRlD’ 输出 hElLO wOrLd;$ ./case.sh lower 输出 Error! Two arguments expected.;$ echo $? 输出 1;$ ./case.sh upper apple fig 输出 Error! Two arguments expected.;$ ./case.sh lowercase DRAGON 输出 Error! ‘lowercase’ command not recognized.;$ echo $? 输出 1;$ ./case.sh apple lower 2> /dev/null;$ echo $? 输出 1

以下是

case.sh

脚本的实现:


#!/bin/bash
if [ $# -ne 2 ]; then
    echo "Error! Two arguments expected."
    exit 1
fi

command=$1
string=$2

case $command in
    lower)
        echo $string | tr '[:upper:]' '[:lower:]'
        ;;
    upper)
        echo $string | tr '[:lower:]' '[:upper:]'
        ;;
    swap)
        echo ${string~~}
        ;;
    *)
        echo "Error! '$command' command not recognized."
        exit 1
        ;;
esac

将上述代码保存为

case.sh

,然后赋予执行权限:


chmod +x case.sh

这样就可以按要求调用该脚本了。

119、编写一个名为 loop.sh 的 shell 脚本,该脚本显示作为命令行参数传递的每个文件的行数。示例:创建 items_1.txt 和 items_2.txt 文件,执行

bash loop.sh items_1.txt

输出

number of lines in 'items_1.txt' is: 3

;执行

bash loop.sh items_1.txt items_2.txt

输出

number of lines in 'items_1.txt' is: 3


number of lines in 'items_2.txt' is: 5


以下是

loop.sh

脚本的内容:


#!/bin/bash
for file in "$@"; do
    lines=$(wc -l < "$file")
    echo "number of lines in '$file' is: $lines"
done

将上述内容保存为

loop.sh

,然后赋予执行权限

chmod +x loop.sh

,即可按要求使用。

120、编写一个名为 read_file.sh 的 shell 脚本,逐行读取文件并将其作为参数传递给 paste -sd, 命令。能否也使用 xargs 命令而非脚本来实现相同功能?

以下是

read_file.sh

脚本的示例:


#!/bin/bash
while IFS= read -r file; do
  paste -sd, "$file"
done < "$1"

使用

xargs

命令的解决方案:


xargs -I {} sh -c 'paste -sd, {}' < list.txt

这里假设文件名为

list.txt

,若文件名不同,需相应修改。

121、编写一个名为add_path的函数,该函数将当前工作目录的路径前缀添加到它接收的参数中,并显示结果。例如,当当前工作目录为/home/learnbyexample时,调用add_path ip.txt report.log ,应输出 /home/learnbyexample/ip.txt /home/learnbyexample/report.log ;当当前工作目录为/home/learnbyexample/cli – computing时,调用add_path f1 ,应输出 /home/learnbyexample/cli – computing/f1。

以下是实现该功能的Bash函数代码:


add_path() {
  local current_dir=$(pwd)
  for arg in "$@"; do
    echo "$current_dir/$arg"
  done
}

将上述代码添加到你的Bash脚本或配置文件中,即可使用

add_path

函数。例如:


# 定义函数
add_path() {
  local current_dir=$(pwd)
  for arg in "$@"; do
    echo "$current_dir/$arg"
  done
}

# 测试函数
add_path ip.txt report.log

122、选项 bash -x 和 bash -v 分别有什么作用?

bash -x

用于在命令执行时打印命令及其参数;

bash -v

是详细模式选项,用于在读取 shell 输入行时将其打印出来。

123、什么是shellcheck,什么时候会使用它?


`shellcheck` 是一个静态分析工具,能为脚本提供警告和建议。可在线使用,也能安装后离线使用。由于 Bash 存在各种易犯错误,无论是初学者还是高级用户,都强烈推荐使用该工具。当编写 Bash 脚本时,为避免常见错误、提高脚本质量,可使用 `shellcheck` 对脚本进行检查。

124、你会使用哪个命令来显示所有或特定环境变量的名称和值?

可以使用printenv命令来显示所有环境变量的名称和值,若提供参数,则仅显示这些变量的值。

125、如果你为一个已有的命令(例如ls)添加了别名,如何调用原始命令而非别名?

可以使用反斜杠前缀(例如

ls

)来避免使用别名,调用原始命令;也可以使用

command ls

来替代转义字符。

126、为什么下面的别名无法正常工作?应该用什么替代?别名

alias ext='echo "${1##*.}"'

无法按预期工作,输入

ext ip.txt

输出

ip.txt

,预期输出为

txt

;输入

ext scores.csv

预期输出

csv

;输入

ext file.txt.txt

预期输出

txt


别名不能直接接收参数,所以

alias ext='echo "${1##*.}"'

无法正常工作。应该使用函数替代,示例如下:


ext() { echo "${1##*.}"; }

这样,调用

ext ip.txt

就会输出

txt

127、如何在当前 shell 会话中移除特定的别名/函数定义?示例如下:先定义别名

alias hw='echo hello world'

并执行

hw

输出

hello world

,然后移除该别名,再次执行

hw

显示

hw: command not found

;再定义函数

hw() { echo hello there ; }

并执行

hw

输出

hello there

,然后移除该函数,再次执行

hw

显示

hw: command not found


要移除别名,可使用

unalias

命令;要移除函数,可使用

unset -f

命令。对于上述示例,移除别名的命令是

unalias hw

,移除函数的命令是

unset -f hw

128、编写一个别名(alias)和一个函数(function),通过将冒号(:)替换为换行符,将 PATH 环境变量的内容分行显示。示例输出如下:$ echo “$PATH” /usr/local/bin:/usr/bin:/bin:/usr/games # 别名 $ a_p /usr/local/bin /usr/bin /bin /usr/games # 函数 $ f_p /usr/local/bin /usr/bin /bin /usr/games

别名


alias a_p='echo $PATH | tr : " 
"'

函数


f_p() { echo $PATH | tr : " 
" }

上述代码中,

tr

命令用于将字符串中的冒号替换为换行符。定义好别名和函数后,就可以使用

a_p


f_p

来分行显示

PATH

环境变量的内容。

129、哪个快捷键可帮助你交互式搜索命令历史记录?

上下箭头键、

Ctrl + p


Ctrl + n

可用于从历史记录中导航先前使用过的命令,可能用于交互式搜索命令历史。

130、快捷键 Alt+b 和 Alt+f 有什么作用?

Alt+b 用于将光标移动到当前或前一个单词的开头;Alt+f 用于将光标移动到下一个单词的末尾。

131、你会使用哪个快捷键来删除光标前直到行首的字符?

Ctrl+u

132、快捷键 Alt+t 和 Ctrl+t 有什么作用?

以下为调整为 Markdown 格式的内容:


Alt+t

(或

Esc+t

)用于交换前两个单词;

Ctrl+t

用于交换前两个字符。例如,若输入

sp

而非

ps

,当光标在

sp

右侧时,按

Ctrl+t

可进行修正。

133、Shift+Insert 和 Shift+Ctrl+v 快捷键有区别吗?

有区别。

Shift+Ctrl+v

是粘贴剪贴板内容;

Shift+Insert

是粘贴最后突出显示的部分,不一定是剪贴板内容。

134、whatis 命令可显示命令的单行描述,但 whatis type 似乎不起作用,应该用什么替代?

可尝试使用 type 命令本身来显示命令类型相关信息。

135、cp命令的 -u、-b 和 -t 选项分别有什么作用?

-u

选项用于只复制源文件中比目标文件更新或目标文件不存在的文件;

-b

选项用于在覆盖目标文件前先进行备份;

-t

选项可用于指定目标目录在源文件之前。

© 版权声明

相关文章

暂无评论

none
暂无评论...