我想缩短我的一个脚本,我有个主意,但我不知道该怎么做。有一段代码如下:
COMMAND="find /etc -type "
case $1:
"directory") $COMMAND d
;;
esac
当然这是简短的版本:) 现在我希望能够缩短它,而不是到处都写那个 $COMMAND,所以我希望有这样的东西:
$COMMAND <the case statement return value>
但我不想使用变量来存储案例的结果。
谢谢 :) 希望你明白我想要什么 :D
编辑 1:可以创建一个函数并将 find 参数作为 Serg 指出的 $1 传递。现在,如果我想在不使用函数的情况下做到这一点,我相信有办法 :D 并不是说 Serg 没有解决这个问题,我只是很好奇 :D
答案1
有几种可能的方法来简化代码。以下是按代码量排序的解决方案:
printf
和参数替换(无错误检查)xargs
和参数替换(无错误检查)find
仅参数替换(无错误检查)- 贯穿案例结构(解决错误检查问题)
- 测试逻辑、xargs 和参数替换
- Bash 函数
- 数组、for 循环、测试和 &&
printf
及参数替代解决方案该函数的一个鲜为人知的特性
printf
是,如果你调用printf "%c" someString
,它将仅打印第一的该字符串的字符。因此,我们可以避免使用带有参数扩展的 case 语句,printf
如下所示:xieerqi:$ cat someScript.sh #!/bin/bash find /etc -type $(printf "%c" $1 )
现在执行:
xieerqi:$ sudo ./someScript.sh directory | head [sudo] password for xieerqi: /etc /etc/logrotate.d /etc/apm /etc/apm/event.d /etc/apm/scripts.d /etc/apm/resume.d /etc/apm/suspend.d /etc/speech-dispatcher /etc/speech-dispatcher/modules /etc/speech-dispatcher/clients
这里的一个限制是我们正在分叉一个进程来调用
printf
,而函数解决方案可以避免这种情况 - 函数和案例结构都是原生 bash 工具。xargs
和参数替换使用 bash 的参数替换,我们可以从变量中截取一个子字符串(例如
${VAR:0:3}
给出 的前 3 个字符VAR
);在这种情况下,我们想要类型directory
或的第一个字符file
。然后我们可以使用xargs
将其作为参数传递给find
echo ${1:0:1} | xargs -I {} find /etc -type {}
手册
find
页提到,对于-type
Solaris 上的标志,有一种称为门文件的东西,用大写字母表示D
,但由于我们使用的是 Linux,所以我们可以说这是一个可以合理忽略的限制。但是,此代码中还有另一个危险 - 如果用户输入
flower
作为$1
参数,则仍将搜索-type f
,因为我们取任何字符串的第一个字符……换句话说,没有错误检查。find
带参数扩展进一步进行参数扩展,我们可以这样做:
find /etc -type ${1:0:1}
基本上,一行命令
find
和变量的子字符串$1
。此外,没有错误检查。失败案例结构
最后三种方法的最大问题是错误检查。当您相信用户不是傻瓜,或者只是为自己编写代码时,它们很有用。现在,在 Java 中,
switch
如果您省略命令,就可以编写一个语句,该语句将针对多种情况运行相同的命令break
。bash
也可以使用;&
终止符来完成。引用自man bash
使用
;&
代替 导致;;
执行继续与下一组模式相关的列表。我们要做的就是测试类型,例如“目录”、“文件”、“块”等,然后使用参数替换来截断第一个字符。像这样
#!/bin/bash case "$1" in "directory") ;& "file");& "block") find /etc -type ${1:0:1} ;; *) exit 1 ;; esac
5.测试逻辑、xargs 和参数替换
Basic idea here is that we're sending $1 variable through pipe to `xargs`, which in turn substitutes it into test (again square brackets). `xargs` in turn builds the actual command that runs by replacing `{}` with whatever was passed to `xargs`. As for test command, it's simple or statement, `EXPRESSION -o EXPRESSION ` , where we test if string $1 is equal to either "file" or "directory string"
echo "$1" | xargs -I {} [ "{}" = "file" -o "{}" = "directory" ] \
&& find /etc -type ${1:0:1}
`xargs` is really useful when you need to process multiple argumens with the same command. Considering that in this case we only have one argument that needs to be processed with the same command , this can be simplified to
[ "$1" = "file" -o "$1" = "directory" ] && find /etc -type ${1:0:1}
Of course the big limitation is that if you test for more than one type, you need longer `[ EXPR1 -o EXPR2 ]` structure with multiple `-o` parts.
功能解决方案
find
命令可以放入函数中,然后可以使用位置参数调用该函数。例如:
function findStuff { find /etc -type "$1" }
这是一个小演示。请注意,我之所以使用,
sudo
是因为普通用户中的很多文件/etc
没有读取权限xieerqi:$ sudo ./someScript.sh directory | head [sudo] password for xieerqi: /etc /etc/logrotate.d /etc/apm /etc/apm/event.d /etc/apm/scripts.d /etc/apm/resume.d /etc/apm/suspend.d /etc/speech-dispatcher /etc/speech-dispatcher/modules /etc/speech-dispatcher/clients xieerqi:$ sudo ./someScript.sh file | head [sudo] password for xieerqi: /etc/hosts.deny /etc/logrotate.d/speech-dispatcher /etc/logrotate.d/pm-utils /etc/logrotate.d/rsyslog /etc/logrotate.d/yate /etc/logrotate.d/apport /etc/logrotate.d/apt /etc/logrotate.d/consolekit /etc/logrotate.d/fail2ban /etc/logrotate.d/cups-daemon xieerqi:$ cat someScript.sh #!/bin/bash function findStuff { find /etc -type "$1" } case "$1" in "directory")findStuff d ;; "file") findStuff f;; esac
数组、for 循环、测试和 &&
这里的基本思想是将用户的输入与列表进行匹配,如果匹配则执行某些操作。我们创建一个要检查的项目数组,有一个测试条件(顺便说一下,方括号是
test
命令的别名),然后运行一个循环来测试 $1 变量。&&
运算符允许执行命令,当且仅当左侧的内容&&
成功时。因此,如果我们在数组中找到一个字符串,我们将执行 find 命令。前面的例子中讨论了 ${1:0:1} - 参数扩展会从匹配的类型中截掉第一个字符。因此,此解决方案具有错误检查功能,并且将大量代码打包到仅 3 行中(如果包括#!
行,则为 4 行)。#!/bin/bash array=("file" "directory" "block"); for TYPE in "${array[@]}"; do [ "$1" = "$TYPE" ] && find /etc/ -type ${1:0:1}; done
答案2
将其放入函数中:
MyFind () {
COMMAND="find /etc -type "
case $1:
"directory") $COMMAND d
;;
esac
}
现在您可以随时使用它作为MyFind $TYPE
关于你的第一条评论
你也可以只将 case 语句放入函数中
FType () {
case $1 in
"directory") echo d;;
"file") echo f;;
esac
}
COMMAND="find /etc -type "
$COMMAND $(FType $TYPE)
答案3
[[ "$1" == "directory" ]] && find /etc -type d
答案4
这只是 Serg 出色的回答中已经很广泛的选项中的另一个想法。
您也许能够使用这个alias
- 可能对您当前的做事方式进行一些细微的改变。
Analias
只是一个单词,你选择将它映射到一个更大的字符串,shell 每次遇到它时都会将其展开。也许最常见的用例是将“默认值”应用于现有命令,如下所示:
alias ls='ls -a --color=auto'
但是,并不要求你的alias
命令必须以现有命令命名 - 或者甚至比其目标模式更短 - 因此你可以例如alias tgzcreator='tar -czvf'
alias
es 与定义它们的 shell 共享生命周期。alias
您可以在 中设置“持久”es ~/.bash_aliases
,其中应该可以通过大多数精心编写的默认.bashrc
脚本等自动获取。
请注意以下几点提示:
- 您无需担心在特定脚本中先前定义的代码是否
alias
会干扰您的代码,只需在其前面加上反斜杠即可确保alias
跳过 ing。例如,我通常alias
cp
会这样做cp -i
以避免意外覆盖内容,但在某些脚本中,我显然想覆盖内容。(我不会使用一些糟糕的解决方法,例如设置已知的未alias
编辑用户!)因此,在该脚本中,我将使用\cp src dst
alias
默认情况下,es 可能不会在 shell 脚本中被调用,因为 shell 脚本会启动它们自己的非交互式 shell 副本。您可以通过expand_aliases
在脚本中设置选项来确保它们被扩展。我从以下地址获得此信息:https://stackoverflow.com/questions/2197461/how-to-set-an-alias-inside-a-bash-shell-script-so-that-is-it-visible-from-the-ou
因此,根据你帖子中提供的有限信息,你可能需要做点什么有点像这样:
shopt -s expand_aliases
alias get_etc_dir='find /etc -type d'
alias get_etc_fil='find /etc -type f'
对于您来说,如果不进行调整,例如将参数化的 inode 类型更改为每个别名后缀,则可能无法实现此目的。这只是用户通常缩短代码片段的另一种选择。无论哪种方式,我都尝试根据我所知道的内容进行全面解释,希望它在某些地方有用。
(此外,我建议将其移至 Unix/Linux SE,假设这对于非 Ubuntu 特定的东西来说是理想的?)