Linux 在bash命令内调用自定义函数
我有以下bash脚本:Linux 在bash命令内调用自定义函数,linux,bash,shell,awk,Linux,Bash,Shell,Awk,我有以下bash脚本: #!/bin/bash find . -maxdepth 1 -mmin +1 -type f -name "240*.ts" | xargs -L 1 bash -c 'mv "${1}" "$(get_crtime${1} | awk '{print $5}').ts"' \; 我们的想法是找到与特定模式匹配的文件(在我的例子中,以“240”开头的文件),并将其从原始名称(240-1458910816045.ts)重命名为所需格式(15:00:16.ts) 在脚
#!/bin/bash
find . -maxdepth 1 -mmin +1 -type f -name "240*.ts"
| xargs -L 1 bash -c 'mv "${1}" "$(get_crtime${1} | awk '{print $5}').ts"' \;
我们的想法是找到与特定模式匹配的文件(在我的例子中,以“240”开头的文件),并将其从原始名称(240-1458910816045.ts)重命名为所需格式(15:00:16.ts)
在脚本中,我使用get_crtime命令,该命令是/etc/bash.bashrc中包含的自定义函数,具有以下实现:
get_crtime() {
for target in "${@}"; do
inode=$(stat -c '%i' "${target}")
fs=$(df "${@}" | awk '{a=$1}END{print a}')
crtime=$(sudo debugfs -R 'stat <'"${inode}"'>' "${fs}" 2>/dev/null |
grep -oP 'crtime.*--\s*\K.*')
printf "%s\t%s\n" "${target}" "${crtime}"
done
}
我得到了期望的输出:
15:00:16
这是文件创建日期的一部分
我的问题是,当我在初始脚本中包含函数调用时,会出现以下错误:
}).ts": -c: line 0: unexpected EOF while looking for matching `)'
}).ts": -c: line 1: syntax error: unexpected end of file
我认为这是由于不正确地调用awk造成的,所以我想删除它,只留下:
find . -maxdepth 1 -mmin +1 -type f -name "240*.ts"
| xargs -L 1 bash -c 'mv "${1}" "$(get_crtime ${1}).ts"' \;
我得到了以下更具启发性的错误:
;: get_crtime: command not found
如何在初始命令中调用bashrc中的自定义函数而不出现最后一个错误?
谢谢大家!
- 操作系统是Ubuntu
- 炮弹爆炸了
export -f get_crtime
这将使它可用于子bash
进程(但不可用于其他shell)
此外,正如@EdMorton指出的,不能在单引号字符串中使用单引号,这是调用awk
的问题所在。因此,您需要想出一种不同的方法,将内部参数引用到awk
,或者修复get_crtime
以仅返回所需的字符串
顺便说一下,您可以考虑使用<代码>查找< /COD> S代码> -Exc< <代码>操作,而不是<代码> XARGS。这将允许您在多个文件上使用循环,这将更有效率
例如不能在单引号分隔的脚本中使用单引号。看:
$ bash -c 'printf "%s\n" "$(date | awk '{print $0}')"'
-bash})": -c: line 0: unexpected EOF while looking for matching `)'
-bash})": -c: line 1: syntax error: unexpected end of file
$ bash -c 'printf "%s\n" "$(date | awk "{print \$0}")"'
Fri, Mar 25, 2016 8:59:31 AM
不过,我不建议您在awk脚本周围使用双引号-为您创建一个脚本来执行mv等操作,或者找到其他实现它的方法来解决函数访问问题。在本例中,使用了文件的修改时间,可以通过stat-c“%y”
获得。xargs-I
参数可以放置文件名两次,第一次用于stat
,第二次用于mv
。然后使用参数扩展bash功能仅从人类可读的stat
输出中提取时间:
find . -maxdepth 1 -mmin +1 -type f -name "240*.ts" | \
xargs -I_ bash -c 'MTIME=$(stat -c '%y' "_") && MTIME=${MTIME#* } && mv "_" ${MTIME%.*}.ts'
你不能
xargs
正在启动一个单独的bash进程,该进程对函数或局部变量一无所知。我建议您停止使用xargs
和friends,学习shell脚本,您可以将其作为for循环。因为您希望保留查找,所以请像文件中的那样在$(find…)中进行查找;执行mv“$file”$(获取时间“$file”);done
@KurtStutsman从不编写在这样的命令输出上运行的for循环,因为给定一些文件名,它很容易被破坏。使用cmd |而IFS=read-r file
或类似的方法来代替。@EdMorton如果你知道文件名的格式和他的情况一样好,那么用这种方法写也没什么错。只有少数情况并非如此。另外,使用while循环会将代码强制放入子shell,并引入它自己的问题。这就像说,如果知道shell变量的内容格式良好,那么将其保留为不带引号没有什么错。只要以稳健的方式去做,你就不会得到任何惊喜和/或养成坏习惯。如果执行子shell会产生问题,请使用流程替换或其他解决方法,请参阅或重新考虑您的方法。
$ bash -c 'printf "%s\n" "$(date | awk '{print $0}')"'
-bash})": -c: line 0: unexpected EOF while looking for matching `)'
-bash})": -c: line 1: syntax error: unexpected end of file
$ bash -c 'printf "%s\n" "$(date | awk "{print \$0}")"'
Fri, Mar 25, 2016 8:59:31 AM
find . -maxdepth 1 -mmin +1 -type f -name "240*.ts" | \
xargs -I_ bash -c 'MTIME=$(stat -c '%y' "_") && MTIME=${MTIME#* } && mv "_" ${MTIME%.*}.ts'