0

--

I need to copy each file which a process has open, by reading its file descriptor in the /proc/[pid]/fd/ directory etc. more specifically I need to find the directory of the file for each pid, then egrep for a regex; files ending in [0-9]$. cp throws an exception:

cp: cannot stat ‘poop.log.2016-01-08T12-34-10’: No such file or directory

function foo {
    local f
    logfile="$(logfile_for_pid)" # calls the function to get file descriptor
    for f in "$logfile"; do
            for i in "$(dirname "$f")"; do
                    echo "ls the dirname: "$i""
                    ls "$i" | egrep -e '[0-9]$' | xargs cp -t /tmp
            done
    done
}

My question would be: how do I pass the ls output as an argument for cp?

also; running directly from the terminal. same error! note; I am new to bash!

$ cp `ls "$dir" | egrep -e '[0-9]$'` /tmp
  • What is the question? – Tom Fenech Jan 10 '16 at 00:49
  • It seems `ls "$dir"` would just list the file names in the directory, not the full path. `find` may be a better option here. See eg http://stackoverflow.com/questions/246215/how-can-i-list-files-with-their-absolute-path-in-linux –  Jan 10 '16 at 00:49
  • @Evert thank you! `find "$PWD"` done the trick. –  Jan 10 '16 at 01:07
  • 4
    @ByronGrogan You should read [Why you shouldn't parse the output of ls(1)](http://mywiki.wooledge.org/ParsingLs) ... same goes to just replacing it with `find` here. – Reinstate Monica Please Jan 10 '16 at 01:34
  • Why do you loop over `"$logfile"`? The loop could only ever run one iteration -- are you trying to avoid running it when the output is empty, or is this just completely redundant? – tripleee Jan 12 '16 at 07:00
  • Looks like `cp -t /tmp "$(dirname "$f")"/*[0-9]` would accomplish what you are spending several lines of pretzel logic to try to do. – tripleee Jan 12 '16 at 07:00
  • I'm guessing there is a race condition -- the file exists when you read the directory, but is removed by the time the `cp` runs. There really isn't any way to avoid that, but you can reduce the time window to make it less likely to happen, or perhaps stop the other process which is meddling with the symlinks for the duration of the copy operation. – tripleee Jan 12 '16 at 07:02

1 Answers1

1

There will very seldom be a reason to pipe the output of the ls utility to anything.

I'm looking at you code thinking that the outermost loop (with f) is most likely unnecessary, since anything you store in $logfile will be treated as a single file name in any case (for f in "$logfile").

This cuts it down to

function foo {
    logfile="$(logfile_for_pid)"

    for i in "$(dirname "$logfile")"; do
        echo "ls the dirname: "$i""
        ls "$i" | egrep -e '[0-9]$' | xargs cp -t /tmp
    done
}

The inner loop may be eliminated, because we know there's only one $logfile:

function foo {
    logfile="$(logfile_for_pid)"

    i="$(dirname "$logfile")"
    echo "ls the dirname: "$i""

    ls "$i" | egrep -e '[0-9]$' | xargs cp -t /tmp
}

And now you'd like to copy all files with a digit at the end of their filenames in that directory to /tmp:

function foo {
    logfile="$(logfile_for_pid)"

    i="$(dirname "$logfile")"
    echo "ls the dirname: "$i""

    cp "$i"/*[0-9] /tmp
}

Or did I misunderstand you?

Kusalananda
  • 14,885
  • 3
  • 41
  • 52