Copying files interactively: "cp: overwrite"

Git*_*Gud 3 shell cp interactive

I'm trying to figure out what words does the -interactive option of cp accepts as input.

For your convenience, here's code that sets up files for experimentation.

touch example_file{1..3}
mkdir example_dir
cp example_file? example_dir
cp -i example_file? example_dir
Run Code Online (Sandbox Code Playgroud)

The shell then asks interactively for each file whether it should be overwritten. It seems to accept all sorts of random input.

cp: overwrite 'example_dir/example_file1'? q
cp: overwrite 'example_dir/example_file2'? w
cp: overwrite 'example_dir/example_file3'? e
Run Code Online (Sandbox Code Playgroud)

I tried looking into the source code of cp, but I don't know C and searching for overwrite is of no help.

As far as I can tell it accepts some words as confirmation for overwriting, and everything else is taken as a no. The problem is even words like ys seem to be accepted as yes, so I don't know what works and what doesn't.

I'd like to know how exactly does this work and to have some proof of it by means of documentation or intelligible snippets of source code.

Kus*_*nda 7

The POSIX standard only specifies that the response need to be "affirmative" for the copying to be carried out when -i is in effect.

For GNU cp, the actual input at that point is handled by a function called yesno(). This function is defined in the lib/yesno.c file in the gnulib source distribution, and looks like this:

bool
yesno (void)
{
  bool yes;

#if ENABLE_NLS
  char *response = NULL;
  size_t response_size = 0;
  ssize_t response_len = getline (&response, &response_size, stdin);

  if (response_len <= 0)
    yes = false;
  else
    {
      /* Remove EOL if present as that's not part of the matched response,
         and not matched by $ for example.  */
      if (response[response_len - 1] == '\n')
        response[response_len - 1] = '\0';
      yes = (0 < rpmatch (response));
    }

  free (response);
#else
  /* Test against "^[yY]", hardcoded to avoid requiring getline,
     regex, and rpmatch.  */
  int c = getchar ();
  yes = (c == 'y' || c == 'Y');
  while (c != '\n' && c != EOF)
    c = getchar ();
#endif

  return yes;
}
Run Code Online (Sandbox Code Playgroud)

如果使用NLS(“国家语言支持”),您可以看到该函数返回true的唯一回复是以大写或小写Y字符开头的响应。丢弃任何附加或其他输入。

如果NLS所使用的,rpmatch()函数被调用,以确定响应是否是肯定的或没有。rpmatch()NLS 库函数的目的是确定给定的字符串是否是肯定的(支持国际化)。

在 BSD 系统上,相应的函数位于src/bin/cp/utils.c

/*
 * If the file exists and we're interactive, verify with the user.
 */
int
copy_overwrite(void)
{
        int ch, checkch;

        if (iflag) {
                (void)fprintf(stderr, "overwrite %s? ", to.p_path);
                checkch = ch = getchar();
                while (ch != '\n' && ch != EOF)
                        ch = getchar();
                if (checkch != 'y' && checkch != 'Y')
                        return (0);
        }
        return 1;
}
Run Code Online (Sandbox Code Playgroud)

这与 GNU 代码中的非 NLS 代码路径基本相同。