user106745
user106745

Reputation: 193

xargs argument not interpreted

I have a directory $dir that contains .txt.xy files and subdirectories with .txt.xy files. I try to iterate over each file and pass the whole path as well as the path without $dir as argument to a program like this:

dir="/path/to/"
suffix=".xy"

find "$dir" -name "*.txt.xy" -print0 | xargs -0 -I {} sh -c 'program "$1" |
  subprogram filename="$2"' _ {} "$(echo {} | sed -e "s#^${dir}##" -e "s#${suffix}\$##")"

$1 is the propper full path but $2 is also the full path as if the pipe in $(...) is never executed. What am I missing here?

Upvotes: 1

Views: 115

Answers (2)

tripleee
tripleee

Reputation: 189387

Your attempt seems rather roundabout. It sounds like you are looking for

find /path/to -name "*.txt.xy" -exec sh -c '
    for f; do
        g=${f##*/}
        program "$f" | subprogram filename="${g%.xy}"
    done' _ {} +

If you really need your parameters to be in variables, maybe pass in the suffix as $0 which isn't used for anything useful here anyway. It's a bit obscure, but helps avoid the mess you had with double quotes.

find /path/to -name "*.txt.xy" -exec sh -c '
    for f; do
        g=${f##*/}
        program "$f" | subprogram filename="${g%"$0"}"
    done' ".xy" {} +

The above simply trims g to the basename which I guess on closer reading you don't want. So pass /path/to in $0 instead, and hardcode .xy inside:

find /path/to -name "*.txt.xy" -exec sh -c '
    for f; do
        g=${f#"$0"/}
        program "$f" | subprogram filename="${g%.xy}"
    done' "/path/to" {} +

or if you really need both to be command-line parameters,

dir="/path/to"
suffix=".xy"
find "$dir" -name "*.txt$suffix" -exec sh -c '
    suffix=$1
    shift
    for f; do
        g=${f#"$0"/}
        program "$f" | subprogram filename="${g%"$suffix"}"
    done' "$dir" "$suffix" {} +

Upvotes: 2

Inian
Inian

Reputation: 85580

One reason for the failure, is that the command substitution with xargs under double quotes is expanded by the shell even before the former is executed. One way to avoid that would be to do the whole substitution inside the sub-shell created by sh -c as

find "$dir" -name "*.txt.xy" -print0 | 
xargs -0 -I {} sh -c '
  f="{}"
  g="$(echo "$f" | sed -e 's|"'^"${dir}"'"||' -e 's|"'\\"${suffix}"$'"||' )"
  program "$f" | subprogram filename="$g"
'

Upvotes: 1

Related Questions