Shell Linux/sh:如何仅列出文件夹中的文件(使用witespace)并将其保存到一行中的变量中

Shell Linux/sh:如何仅列出文件夹中的文件(使用witespace)并将其保存到一行中的变量中,shell,printf,sh,whitespace,7zip,bash,Shell,Printf,Sh,Whitespace,7zip,Bash,我尝试获取该格式的文件列表(使用witespaces): “file1.html”“file 2.php”“file_3.php” 输出: "/volume1/web/.htaccess" "/volume1/web/file.html" "/volume1/web/a b.php" 输出非常完美,但是。。。如何将此输出放入变量? 我这样做 IFS=$'\n' for file in $(find "${WEB_DIR}" -mindepth 1 -maxdepth 1 -type f) ;

我尝试获取该格式的文件列表(使用witespaces):

“file1.html”“file 2.php”“file_3.php”

输出:

"/volume1/web/.htaccess" "/volume1/web/file.html" "/volume1/web/a b.php"
输出非常完美,但是。。。如何将此输出放入变量?

我这样做

IFS=$'\n'
for file in $(find "${WEB_DIR}" -mindepth 1 -maxdepth 1 -type f) ; do
  mystring+=$(printf "\"$file\" ")
done

echo ${mystring}
在输出中,我有:

tmp.sh: line 48: mystring+="/volume1/web/.htaccess" : not found
注:

  • 下面的答案接受了问题的前提:使用双引号文件路径列表构建单个字符串值,如问题中所示(
    “/volume1/web/.htaccess”“/volume1/web/file.html”“/volume1/web/ab.php”

  • 但是,OP最终希望将该字符串作为另一个命令的一部分使用,这是行不通的,因为当您引用字符串变量时,嵌入的双引号不再被识别为标识单独参数的字符串分隔符

    • 正确的解决方法是使用
      查找-exec…+
      (在本例中)或通常使用
      xargs
      将文件名列表作为操作数(参数)传递给另一个命令;e、 例如,要将文件名传递给命令
      foo
      {}
      严格传递所有文件路径,无论它们是否包含空格):
      find“${WEB_DIR}”-mindepth 1-maxdepth 1-type f-exec foo-bar{}+

    • 如果文件名列表不在目标命令行的末尾,则需要一个中间的
      sh-c
      命令:
      find“${WEB_DIR}”-mindepth 1-maxdepth 1-type f-exec sh-c'foo-bar“$@”-baz'-{}+


您已经标记了您的问题,但是您的shebang行目标,其中的Bash扩展不能保证可用

在您的情况下(听起来您正在使用
dash
,它在Ubuntu上充当
/bin/sh
):

  • ANSI C带引号的字符串,如
    $'\n'
    不可用-
    $'\n'
    扩展为文字
    $\n

    • 这意味着这3个文字字符中的任何一个
      $
      \
      n
      用作字段分隔符-在您的情况下,这恰好起作用,因为文件路径恰好不包含这些字符
  • 运算符
    +=
    无法识别-整个令牌
    mystring+=“/volume1/web/.htaccess”
    被视为命令名,这会导致您看到的错误

可能的解决办法:

  • 如果确实要以Bash为目标,请替换
    #/bin/sh
    #/bin/bash

    • 请注意,要使
      bash
      代码完全健壮,除了设置
      $IFS
      之外,还应关闭globbing(
      set+f
    • 您的代码可以简化-请参阅下文
  • 如果不是(如果您的代码必须是可移植的),您必须找到与POSIX兼容的替代方案-请参阅下文


这里有一个便携式解决方案(适用于任何兼容POSIX的
sh
):



使用(
bash
等价物
,我不太清楚为什么我们要麻烦使用变量的中间步骤:

find "${WEB_DIR}" -mindepth 1 -maxdepth 1 -type f -print0 | xargs -0 /usr/syno/bin/7z \
a "${BACKUP_DIR}/backup_webfiles_${TIMESTAMP}.7z" -xr!thumbs.db -xr!@eaDir -xr!@tmp \
-xr!#recycle -xr!lost+found -xr!.DS_Store -t7z -m0=lzma2 -ms=off -mhe -mmt -mx9 \
-v${SPLIT_VOLUME} -p"${PASSWORD}"

我不确定您是否必须告诉7z文件来自stdin,因此您可能必须在“${only_files}”处添加连字符(-)过去是???

OP的后续问题被错误地作为答案发布,删除后,您的答案的上下文丢失。您对中间变量的看法是正确的。它不仅没有必要,而且不起作用。通常,您不需要使用
xargs
查找
,因为
-exec
操作c直接调用命令。
7z
作为
xargs
目标命令,不会通过stdin接收文件名;相反,
xargs
将它们作为参数列表传递到命令行末尾。
while IFS= read -r file; do
  mystring="$mystring$(printf "\"$file\" ")"
done <<EOF
$(find "${WEB_DIR}" -mindepth 1 -maxdepth 1 -type f)
EOF

echo "$mystring"
IFS= read -r mystring <<EOF
$(find "${WEB_DIR}" -mindepth 1 -maxdepth 1 -type f -exec printf '"%s" ' {} +)
EOF

echo "$mystring"
IFS= read -r mystring < \
  <(find "${WEB_DIR}" -mindepth 1 -maxdepth 1 -type f -exec printf '"%s" ' {} +)

echo "$mystring"
IFS= read -r mystring < <(find "${WEB_DIR}" -mindepth 1 -maxdepth 1 -type f -printf '"%p" ')

echo "$mystring"
find "${WEB_DIR}" -mindepth 1 -maxdepth 1 -type f -print0 | xargs -0 /usr/syno/bin/7z \
a "${BACKUP_DIR}/backup_webfiles_${TIMESTAMP}.7z" -xr!thumbs.db -xr!@eaDir -xr!@tmp \
-xr!#recycle -xr!lost+found -xr!.DS_Store -t7z -m0=lzma2 -ms=off -mhe -mmt -mx9 \
-v${SPLIT_VOLUME} -p"${PASSWORD}"