Bash:在空间上分裂,但不在逃生空间上分裂



我正在尝试编写一个 bash 脚本来读取用户的输入(一些文件,以便用户可以在完成TAB使用)并将它们复制到特定文件夹中。

#/bin/bash
read -e files
for file in $files
do
    echo $file
    cp "$file" folder/"$file"
done

可以:file1 file2 ...

或者使用 : file*(即使文件夹中有一个带空格的文件名)。

但它不适用于带有反斜杠转义空格的文件名 例如:file with space转义空格将被忽略,字符串在每个空格上被拆分,甚至转义。

我看到了有关报价,printf,IFS,阅读和同时...我认为这是非常基本的 bash 脚本,但我找不到一个好的解决方案。你可以帮我吗?

在未加引号的扩展之前清除IFS将允许通配继续,同时防止字符串拆分:

IFS=$' tn' read -e -a globs  # read glob expressions into an array
IFS=''
for glob in "${globs[@]}"; do  # these aren't filenames; don't claim that they are.
  files=( $glob )              # expand the glob into filenames
  # detect the case where no files matched by checking whether the first result exists
  # these *would* need to be quoted, but [[ ]] turns off string-splitting and globbing
  [[ -e $files || -L $files ]] || {
    printf 'ERROR: Glob expression %q did not match any files!n' "$glob" >&2
    continue
  }
  printf '%qn' "${files[@]}"  # print one line per file matching
  cp -- "${files[@]}" folder/  # copy those files to the target
done

请注意,我们在read操作期间强制执行默认IFS=$' tn',这可确保在该阶段将不带引号的空格视为数组元素之间的分隔符。后来,有了files=( $glob ),相比之下,我们有IFS='',所以空格不再能把各个名字分开。

您可以将文件名读入数组,然后遍历数组元素:

read -e -a files
for file in "${files[@]}"; do
    echo "$file"
    cp "$file" folder/"$file"
done
无论你

如何引用,读入单个字符串都是行不通的:字符串要么在每个空格处被拆分(当不加引号时),要么根本不被分割(当被引号时)。有关详细信息,请参阅此规范问答(您的案例是列表中的最后一项)。

这可以防止通配,即file*不膨胀。有关考虑到这一点的解决方案,请参阅查尔斯的答案。

有一个

功能齐全的文件和 glob 解决方案。

在使用 xargs(能够保留带引号的字符串)的帮助下。但是您需要在引号内写入带有空格的文件:

"file with spaces"

使用脚本时:取消引用已读内容并引用listOfFiles作业。

我也在利用@CharlesDuffy职位的一些想法(感谢查尔斯)。

#!/bin/bash
# read -e listOfFiles
listOfFiles='file1 file* "file with spaces"'
IFS=''
while IFS='' read glob; do     # read each file expressions into an array
  files=( $glob )              # try to expand the glob into filenames
  # If no file match the split glob
  # Then assume that the glob is a file and test its existence
  [[ -e $files || -L $files ]] || {
      files="$glob"
      [[ -e $files || -L $files ]] || {
          printf 'ERROR: Glob "%q" did not match any file!n' "$glob" >&2
          continue
      }
  }
  printf '%qn' "${files[@]}"  # print one line per file matching
  cp -- "${files[@]}" folder/  # copy those files to the target
done < <(xargs -n1 <<<"$listOfFiles")

请注意,Charles Duffy 和 user2350426 的答案不会保留转义的*;它们也会扩展它们。

然而,本杰明的做法根本做不了流星。他错了,你可以先把你的 glob 放在一个字符串中,然后将它们加载到数组中。

然后它将按预期工作:

globs='file1 file 2 file-* file* file""'  # or read -re here 
# Do splitting and globbing:
shopt -s nullglob
eval "files=( $globs )"
shopt -u nullglob
# Now we can use ${files[@]}:
for file in "${files[@]}"; do
    printf "%sn" "$file"
done

另请注意,使用 nullglob 忽略不可扩展的球体。您可能还希望使用failglob或者,为了进行更精细的控制,可以使用上述答案中的代码。

在函数内部,您可能希望declare变量,以便它们保持局部。

相关内容

  • 没有找到相关文章

最新更新