Linux 在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) 在脚

我有以下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)

在脚本中,我使用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'