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
错误,即该条件表达式为什么会失败?
$ 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
。
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 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
。
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
选项可用于指定目标目录在源文件之前。