Bash 命令使用技巧与新手常见错误解决
1. 跨单词边界替换
1.1 命令行替换限制
在命令行中使用
!!:s/a/b/
语法进行替换时,替换操作只能在一个单词内部进行。例如,不能使用
s/-g -A/-gA/
这样的命令,因为在 bash 中
-g
和
-A
是两个独立的单词,替换表达式不能跨越单词边界。
1.2 全局替换
如果想替换命令行中某个表达式的所有出现,可以在
s
前加
g
(表示全局替换)。示例如下:
$ /usr/bin/somewhere/someprog -g -s -yknots -w /tmp/soforthandsoon
...
$ !!:gs/s/S/
/usr/bin/Somewhere/Someprog -g -S -yknotS -w /tmp/SoforthandSoon
这里的
g
必须放在
s
前面,因为在 sed 语法中,如果
g
放在
s
后面,
g
后面的字符会被视为要追加到命令后的新文本。
1.3 跨单词边界替换解决方案
当需要进行跨单词边界的替换时,可以使用脱字符(
^
)替换机制。操作步骤如下:
1. 在命令行输入以
^
开头,接着是要替换的文本。
2. 再输入一个
^
,然后是新的文本。
3. 如果要在行尾添加更多文本,需要输入第三个
^
。
示例如下:
$ /usr/bin/somewhere/someprog -g -A -yknot -w /tmp/soforthandsoon
...
$ ^-g -A^-gB^
/usr/bin/somewhere/someprog -gB -yknot -w /tmp/soforthandsoon
如果要删除某些内容,只需将新文本留空。例如:
$ /usr/bin/somewhere/someprog -g -A -yknot /tmp
...
$ ^-g -A^^
/usr/bin/somewhere/someprog -yknot /tmp
...
$ ^knot^
/usr/bin/somewhere/someprog -gA -y /tmp
2. 重用参数
2.1 问题描述
使用
!!
可以轻松重用最后一个命令,但有时可能只需要重用最后一个参数,该如何操作呢?
2.2 解决方案
-
使用
!$表示最后一个命令的最后一个参数。 -
使用
!:1表示命令行中的第一个参数,!:2表示第二个参数,依此类推。
2.3 示例
在编程中,经常会对同一个文件进行编辑和编译操作,使用
!$
可以节省大量输入并避免错误。示例如下:
$ vi /some/long/path/name/you/only/type/once
...
$ gcc !$
gcc /some/long/path/name/you/only/type/once
...
$ vi !$
vi /some/long/path/name/you/only/type/once
...
$ gcc !$
gcc /some/long/path/name/you/only/type/once
如果需要的参数在命令行中间,可以使用带编号的 “bang - 冒号” 命令获取。例如:
$ munge /opt/my/long/path/toa/file | more
...
$ vi !:1
vi /opt/my/long/path/toa/file
3. 自动补全路径名
3.1 问题描述
有些路径名很长,bash 能否提供帮助呢?
3.2 解决方案
当不确定如何输入完整路径名时,按下 Tab 键,bash 会尝试为你补全路径名。具体操作步骤如下:
1. 输入部分路径名后按下 Tab 键。
- 如果没有匹配项,bash 可能没有反应。
- 如果有多个匹配项,再次按下 Tab 键,bash 会列出所有选择,并重复你输入到当前位置的命令,方便你继续输入。
2. 输入更多字符以消除歧义,然后再次按下 Tab 键,bash 会补全参数。
3.3 示例
$ ls
myfile.c myfile.o myfile.zip
$ ls -lh myfile<tab><tab>
myfile.c myfile.o myfile.zip
$ ls -lh myfile.z<tab>ip
-rw-r--r-- 1 me mygroup 1.9M 2006-06-06 23:26 myfile.zip
$ unzip -l myfile<tab>.zip
bash 还能根据命令类型限制选择范围,例如输入 “unzip” 后按 Tab 键,只会补全以
.zip
结尾的文件。
4. 安全使用命令
4.1 问题描述
在输入命令时很容易输入错误字符,对于简单的 bash 命令,这可能会导致严重后果,如移动或删除错误的文件。当涉及模式匹配时,一个小的输入错误可能会导致与预期截然不同的结果。该如何避免呢?
4.2 解决方案
- 使用历史命令和键盘快捷键重复参数,减少输入错误。
-
如果需要进行复杂的文件模式匹配,先使用
echo命令测试模式是否正确,确认无误后再使用!$执行实际命令。 -
在使用历史命令时,可以添加
:p修饰符,让 bash 只打印命令而不执行,以此检查历史替换是否正确。
4.3 示例
$ ls
ab1.txt ac1.txt jb1.txt wc3.txt
$ echo *1.txt
ab1.txt ac1.txt jb1.txt
$ echo [aj]?1.txt
ab1.txt ac1.txt jb1.txt
$ echo ?b1.txt
ab1.txt jb1.txt
$ rm !$
rm ?b1.txt
添加
:p
修饰符的示例:
$ echo ?b1.txt
ab1.txt jb1.txt
$ rm !$:p
rm ?b1.txt
5. 新手常见错误及解决方法
5.1 忘记设置执行权限
5.1.1 问题描述
编写好脚本后尝试运行,却收到权限拒绝的错误信息。示例如下:
$ ./my.script
bash: ./my.script: Permission denied
5.1.2 解决方案
- 方法一:显式调用 bash 并将脚本名作为参数传递:
$ bash my.script
- 方法二:为脚本设置执行权限,以便直接运行:
$ chmod a+x my.script
$ ./my.script
5.1.3 讨论
如果打算多次使用该脚本,建议设置执行权限。设置权限后,脚本使用起来更像一个命令,无需每次都显式调用 bash。常见的 shell 脚本权限设置为 0700(仅所有者具有读、写、执行权限)和 0755(所有用户具有读和执行权限)。
5.2 修复 “No such file or directory” 错误
5.2.1 问题描述
按照设置执行权限的方法操作后,运行脚本却收到 “No such file or directory” 错误。
5.2.2 解决方案
- 尝试显式使用 bash 运行脚本:
$ bash ./busted
- 如果脚本可以正常运行,可能是权限错误或 shebang 行存在拼写错误。
- 如果出现更多错误,可能是文件的行结尾格式不正确。这种情况可能是在 Windows 上编辑文件(例如通过 Samba)或复制文件导致的。可以使用 `dos2unix` 程序修复,或者参考相关方法将 DOS 文件转换为 Linux 格式。需要注意的是,使用 `dos2unix` 可能会创建新文件并删除旧文件,这会改变文件的权限、所有者或组,还可能影响硬链接,因此可能需要再次使用 `chmod` 设置权限。
5.2.3 示例
$ cat busted
#!/bin/bash -
echo "Hello World!"
# 正常运行
$ ./busted
Hello World!
# 如果文件有 DOS 行结尾
$ ./busted
: invalid option
Usage: /bin/bash [GNU long option] [option] ...
# 不同的 shebang 行
$ cat ./busted
#!/usr/bin/env bash
echo "Hello World!"
$ ./busted
: No such file or directory
5.3 忘记当前目录不在 $PATH 中
5.3.1 问题描述
编写好脚本并设置了执行权限,但运行脚本时收到 “command not found” 错误。示例如下:
$ my.script
bash: my.script: command not found
5.3.2 解决方案
-
不推荐将当前目录添加到
$PATH变量中。 -
在脚本名前加上
./来引用脚本,例如:
$ ./my.script
5.3.3 讨论
初学者经常忘记在要执行的脚本名前加上
./
。对于经常使用的脚本,可以将它们放在主目录下的
bin
目录中,并将该目录添加到
$PATH
变量中,这样就无需每次都加
./
。重要的是要将修改
$PATH
变量的操作放在正确的启动脚本中,建议放在 bash 的登录配置文件中,如
~/.bash_profile
、
~/.bash_login
或
~/.profile
中。例如,在
~/.bash_profile
中添加以下行:
PATH="${PATH}:$HOME/bin"
5.4 脚本命名为 test
5.4.1 问题描述
编写了一个 bash 脚本并命名为
test
,设置了执行权限并将其放在
$PATH
中的某个目录下,但运行时没有任何反应。
5.4.2 解决方案
将脚本命名为其他名称,因为
test
是 shell 内置命令。
5.4.3 讨论
使用
type
命令可以查看
test
是 shell 内置命令:
$ type test
test is a shell builtin
由于
test
是内置命令,调整路径无法覆盖它。不建议为其创建别名,建议将脚本重命名,或者使用路径名调用,如
./test
或
/home/path/test
。
5.5 期望更改导出变量
5.5.1 问题描述
初学者常犯的一个错误是将导出的 shell 变量当作编程环境中的全局变量。实际上,导出变量是单向的,它们会包含在被调用的 shell 脚本的环境中,但如果在被调用脚本中更改了这些变量的值,调用脚本不会看到这些更改。
5.5.2 示例
以下是两个脚本的示例:
$ cat first.sh
#
# a simple example of a common mistake
#
# set the value:
export VAL=5
printf "VAL=%d\n" $VAL
# invoke our other script:
./second.sh
#
# now see what changed (hint: nothing!)
printf "%b" "back in first\n"
printf "VAL=%d\n" $VAL
$ cat second.sh
printf "%b" "in second\n"
printf "initially VAL=%d\n" $VAL
VAL=12
printf "changed so VAL=%d\n" $VAL
运行
first.sh
的结果如下:
$ ./first.sh
VAL=5
in second
initially VAL=5
changed so VAL=10
back in first
VAL=5
5.5.3 解决方案
避免将导出变量当作可在调用脚本和被调用脚本之间双向修改的全局变量。
综上所述,通过掌握这些 bash 命令的使用技巧和避免新手常见错误,可以提高命令行操作的效率和准确性。在实际使用中,要根据具体情况选择合适的方法,并注意细节,以确保命令的正确执行。
6. 技巧总结与对比
6.1 替换技巧对比
为了更清晰地理解不同替换方式的使用场景和特点,我们将跨单词边界替换的几种方法进行对比,如下表所示:
| 替换方式 | 适用场景 | 示例 | 注意事项 |
| — | — | — | — |
|
!!:s/a/b/
| 单词内替换 |
!!:s/old/new/
| 只能在一个单词内部进行替换 |
|
!!:gs/a/b/
| 全局替换 |
!!:gs/s/S/
|
g
必须在
s
前,用于替换命令行中所有匹配项 |
|
^old^new^
| 跨单词边界替换 |
^-g -A^-gB^
| 可跨越单词边界,第三个
^
用于行尾追加内容 |
6.2 参数重用与自动补全流程
下面是参数重用和自动补全路径名的操作流程 mermaid 流程图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B{操作类型}:::decision
B -- 参数重用 --> C(使用 !$ 或 !:n):::process
C --> D(执行命令):::process
B -- 自动补全 --> E(输入部分路径名):::process
E --> F(按下 Tab 键):::process
F --> G{是否有匹配项}:::decision
G -- 无 --> H(继续输入):::process
H --> F
G -- 有多个 --> I(再次按下 Tab 键):::process
I --> J(列出选择):::process
J --> K(输入更多字符消除歧义):::process
K --> F
G -- 唯一匹配 --> L(补全路径名):::process
L --> D
D --> M([结束]):::startend
6.3 安全使用与错误处理流程
安全使用命令和处理新手常见错误也有相应的流程,以下是 mermaid 流程图展示:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(编写命令):::process
B --> C{是否涉及模式匹配}:::decision
C -- 是 --> D(使用 echo 测试模式):::process
D --> E{模式是否正确}:::decision
E -- 否 --> B
E -- 是 --> F(使用 !$ 执行命令):::process
C -- 否 --> F
F --> G{是否出现错误}:::decision
G -- 是 --> H{错误类型}:::decision
H -- 权限问题 --> I(设置执行权限):::process
I --> F
H -- 文件路径问题 --> J(检查 shebang 行和行结尾):::process
J --> F
H -- 命令未找到 --> K(添加 ./ 或修改 PATH):::process
K --> F
H -- 脚本命名问题 --> L(重命名脚本):::process
L --> F
H -- 导出变量问题 --> M(避免双向修改):::process
M --> F
G -- 否 --> N([结束]):::startend
7. 实际应用案例
7.1 编程项目中的应用
在一个编程项目中,经常需要对源代码文件进行编辑、编译和调试等操作。假设项目中有一个源文件
main.c
,我们可以利用前面介绍的技巧提高操作效率。
-
编辑和编译
:
$ vi main.c
# 编辑完成后编译
$ gcc !$
# 再次编辑
$ vi !$
# 再次编译
$ gcc !$
- 文件清理 :如果项目生成了一些临时文件,我们可以使用模式匹配和安全执行的方法进行清理。
$ ls
main.c main.o a.out
$ echo *.o
main.o
$ rm !$
7.2 系统管理中的应用
系统管理员在日常工作中需要执行各种命令,处理大量文件和目录。例如,管理用户的脚本文件,我们可以使用自动补全和参数重用技巧。
-
脚本执行
:
$ cd /home/users/scripts
$ ls -lh user_script<tab>
$ ./user_script.sh
# 再次执行相同脚本
$ !!
- 权限管理 :如果需要为新的脚本设置执行权限,可以使用权限设置技巧。
$ chmod a+x new_script.sh
8. 总结与建议
8.1 总结
本文详细介绍了 bash 命令的使用技巧和新手常见错误的解决方法。包括跨单词边界替换的多种方式、参数重用、自动补全路径名、安全使用命令等技巧,以及忘记设置执行权限、文件路径错误、脚本命名冲突、导出变量问题等新手常见错误的处理方法。通过实际案例展示了这些技巧和方法在编程项目和系统管理中的应用。
8.2 建议
- 多实践 :掌握这些技巧和方法需要不断地实践,通过实际操作加深理解和记忆。
- 注意细节 :在使用命令时,要注意细节,如命令的语法、参数的顺序、文件的权限和路径等,避免因小错误导致严重后果。
- 学习文档 :bash 有丰富的文档和手册,可以进一步学习和了解更多高级功能和用法,不断提升自己的技能水平。
通过以上的学习和实践,相信你能够更加熟练地使用 bash 命令,提高工作效率,避免常见错误。
超级会员免费看
9

被折叠的 条评论
为什么被折叠?



