v01d
v01d

Reputation: 327

Call a custom function inside a bash command

I have the following bash script:

#!/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"' \;

The idea is to find files that are older than one minute matching a certain pattern (in my case, files that start with '240') and rename them from their original name (240-1458910816045.ts) to a desired format (15:00:16.ts).

Inside the script I am using get_crtime command which is a custom function included in /etc/bash.bashrc and has the following implementation:

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
}

When I call the function from the shell, like this:

get_crtime 240-1458910816045.ts | awk '{print $5}'

I get the desired output:

15:00:16

Which is a portion from the file creation date.

My problem is when I include the function call inside my initial script I get the following error:

}).ts": -c: line 0: unexpected EOF while looking for matching `)'
}).ts": -c: line 1: syntax error: unexpected end of file

I think this is caused by incorrect invoking of awk, so I thought to remove it and leave just:

find . -maxdepth 1 -mmin +1 -type f -name "240*.ts" 
| xargs -L 1 bash -c 'mv "${1}" "$(get_crtime ${1}).ts"' \;

I get the following error, which is more suggestive:

;: get_crtime: command not found

How can I call the custom function inside the bashrc inside the initial command without getting the last error?

Thank you!

Upvotes: 2

Views: 2214

Answers (3)

rici
rici

Reputation: 241701

You need to export the function:

export -f get_crtime

That will make it available to child bash processes (but not to other shells).

Also, as @EdMorton points out, you cannot use single quotes inside a single quoted-string, which was the problem with the invocation of awk. So you'll need to come up with a different way of quoting the interior argument to awk, or fix get_crtime to just return the string you want.

By the way, you might consider using finds -exec action instead of xargs. That would allow you to use a loop over a number of files, which would be a bit more efficient.

eg.

find . -maxdepth 1 -mmin +1 -type f -name "240*.ts" \
     -exec bash -c 'for f in "$@"; do
                      mv "$f" "$(get_crtime "$f" | awk {print\$5}).ts"
                    done' _ {} +

Upvotes: 0

Sergei Voronezhskii
Sergei Voronezhskii

Reputation: 2362

In this example, used modification time of file, which can be get by stat -c '%y'. The xargs -I param creates possibility to place file name two times, first for stat, second for mv. Then using Parameter Expansion bash features to extract only time from human readable stat output:

find . -maxdepth 1 -mmin +1 -type f -name "240*.ts" | \
xargs -I_ bash -c 'MTIME=$(stat -c '%y' "_") && MTIME=${MTIME#* } && mv "_" ${MTIME%.*}.ts'

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 203324

You can't use single quotes inside a single-quote delimited script. Look:

$ 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

I'm not recommending you use double quotes around your awk script though - create a script to do the mv, etc. for you or figure out some other way to implement it that'll solve your function access problem too.

Upvotes: 1

Related Questions