引用具有混合字符串和多个变量的选项?

Quoting options with mixed strings and multiple vars?

提问人:Wolfpack'08 提问时间:11/25/2022 最后编辑:John KugelmanWolfpack'08 更新时间:11/28/2022 访问量:66

问:

目标:

我偷偷地怀疑我错误地进行了通配,因为无法通过多个高级字符串和 var 混合的明确示例找到令人满意的解释。

我尝试执行的操作在最后一行,目标是输出 outputdirectory + filebasename + outputextension。不幸的是,有太多的变数,尽管阅读了多本手册,但我确信自己犯了错误。

#!/bin/bash

echo Input directory name like ./path/to: 
read -r varin

echo Input directory name like ./path/to: 
read -r varout

if [ ! -d "${varout}" ]; then
  mkdir -p "${varout}";
fi

for file in ${varin}; do pconvert -i "${file}" -o "${varout}"/"${file%%.*}".txt; done

错误:File './inputs/outputs/*/.txt' already exists. Overwrite ? [y/N] ^C

意外行为:

  1. 我必须写而不是写,这是出乎意料的。我希望 bash 查找一个目录,然后遍历该目录中的文件:这很好,但它表明我没有理解代码。./inputs/*./inputs
  2. 假设我键入 ,此脚本尝试在每次迭代时创建,而不是 。第 15 行最后一个操作的目标是清理目录,清理扩展,并使用新路径 + basename + newextension。有点像瞎子牵着瞎子,但我觉得这只能和我使用引号有关?./inputs/outputs/*./inputs/outputs/*.txt./inputs/outputs/inputname.txt

我使用的资源:

根据这个链接,我可能应该做这样的事情:

convertdoc -i "$'{file}'" --pdfconvert -o "$'{outputDir}'/$'{file%%.*}'.odf

但我从朋友那里得到了不同的意见。到目前为止,我被告知不要使用尾随引号,只使用半引号,在美元符号之前和之后都使用引号,并且要向下引号,仅举几例。

示例输入:

$HOME/pdfdl/ardvarks.pdf
$HOME/pdfdl/ants.pdf
$HOME/pdfdl/canines.pdf
$HOME/pdfdl/cats.tmp.pdf
bash glob 报价

评论

1赞 markp-fuso 11/25/2022
将您的代码(以及 shebang)剪切粘贴到 shellcheck.net 中并进行建议的更改;第一个(明显的)问题...... 应该是(分号是语法,并且当前编码实际上被视为变量引用的一部分)for file in "$varin;"for file in "$varin";bash
1赞 markp-fuso 11/25/2022
根据实际输入值,可能会出现运行时问题,因此提供一些导致问题的示例输入也可能有所帮助
1赞 Fravadona 11/25/2022
for file in "$varin"; do ...; donefile=$varin; ...;
1赞 M. Nejat Aydin 11/25/2022
你可能想要.此外,该变量不会在任何地方使用,并且变量 and 不会初始化。for file in "$varin"/*varoutoutdiroutputDir
1赞 markp-fuso 11/25/2022
还要考虑启用调试模式 (; 禁用),运行脚本,并查看调试输出以查看正在执行的操作;如果目的是读取目录中的文件列表,则可能需要类似set -xset +xbash$varinfor file in "$varin"/*; do ...; done

答:

0赞 Eric Marceau 11/27/2022 #1

您的脚本存在一些缺陷。“for”语句并没有做你认为的那样。你没有给它一个表达式来匹配/扩展,所以你只有一个包含 1 个项目的列表,即 varin,只有目录,而不是实际的 PDF 文件。

从您的问题中并不完全清楚您要转换的内容,但输入文件名列表澄清了这一点。

我尝试使用 linux 的基本工具,所以我使用“pdftotext”而不是您上面提到的两个。

至于“${file%%.*}”,我更喜欢显式地做一些隐式形式对初学者/复习来说过于“晦涩难懂”的动作。我更喜欢看到事物如何转换的实际流程,因此在下面的脚本版本中使用了 basename

#!/bin/sh

START=`pwd`

echo "Input directory name (./path/to)  => \c"
#read -r varin
varin=${START}/TESTin

echo "Input directory name (./path/to)  => \c"
#read -r varout
varout=${START}/TESTout

if [ ! -d "${varout}" ]; then
  mkdir -p "${varout}";
fi

cd "${varin}"
if [ $? -ne 0 ] ; then  echo "\n Unable to set '${varin}' as work directory for input file scanning.\n" ; exit 1 ; fi

for file in *.pdf
do
    #pdfconvert -i "${file}" -o "${varout}"/"${file%%.*}".txt
    BASE=`basename "${file}" ".pdf" `
    #pdftotext -eol unix -nopgbrk "${file}" "${varout}/${file%%.*}.txt"
    pdftotext -eol unix -nopgbrk "${file}" "${varout}/${BASE}.txt" 2>>errlog
done

评论

0赞 KamilCuk 11/27/2022
请使用 shellcheck 检查您的脚本。引用变量扩展。无需检查目录是否不存在 - 他已经这样做了。不要使用 - 首选 .不要使用反引号 - 使用 .cd "${varin}"mkdir -p[ $? -ne 0 ]if ! cd "$varin"; then$(...)
0赞 Wolfpack'08 11/28/2022
@KamilCuk 所以会是吗?$(...)START=$(pwd)
0赞 Wolfpack'08 11/28/2022
我尝试使用KamilCuk建议的有和没有编辑的版本:尽管已经创建并填充了TESTin,但我还是收到了一些错误消息,例如.line 18: cd: ./TESTin: No such file or directory \n Unable to set './TESTin' as work directory for input file scanning.\n
0赞 KamilCuk 11/28/2022
would it be START=$(pwd)是的,或者只是或真的只是使用 weell,这表明该目录不存在。START=$PWD$PWDI get some error messages like./TESTin
0赞 Eric Marceau 11/28/2022
@KamilCuk,我解释了为什么我以这种方式做事。它们不是最紧凑的,也不是最高效的,但它们使事情变得明确/可见,符合我的口味......他们的工作方式没有错。是的,我应该引用“${varin}”。这是一个疏忽。
0赞 KamilCuk 11/27/2022 #2

考虑使用参数。我会dp:

#!/bin/bash
varout=$1

mkdir -p "$varout"
for file in "$@"/*; do
      # https://stackoverflow.com/questions/965053/extract-filename-and-extension-in-bash
      filename="${file##*/}"
      filename_without_ext="${filename%.*}"

      pconvert -i "$file" -o "$2/$filename_without_ext".txt
done

然后执行以下操作:

./script.sh /input /output

我必须写 ./inputs/* 而不是 ./inputs,这是出乎意料的。我希望bash会寻找一个目录,然后遍历该目录中的文件

我不明白你的困惑。 展开到目录内的条目列表。如果你键入它只是 ,当你键入时,它会扩展到文件列表。如果两者的意思相同,我会感到意外。*./inputs./inputs./inputs/*${varin}

此外,当路径包含另一个 .它删除了与 匹配的最后缀。当那时将输出为空 - 因为以点开头,匹配所有内容。${file%%.*}..*file=./anything/file.txtecho "${file%%.*}"file=..*

假设我键入 ./inputs/outputs/,此脚本尝试创建 ./inputs/outputs/.txt

否,错误消息建议它尝试创建 ./inputs/outputs/*/.txt

我不明白您希望输出如何扩展 glob 表达式。正如您所说,不是多个新路径,这将扩展到。The goal in the ... use the new path*

根据这个链接,我可能应该做这样的事情: convertdoc -i “$'{file}'” --pdfconvert -o “$'{outputDir}'/$'{file%%.*}'.odf

该链接中从未使用过引用样式。考虑重读一遍。"$'{something}'"

评论

1赞 KamilCuk 11/28/2022
(1)我不明白,用.(2)我不明白它到底是在哪里附加的。如果你询问该行,那么你的要求状态是“使用新路径 + basename + newextension”——它是“newextension”,而不是同一个扩展名。set -x"$varout/$filename_without_ext".txt
0赞 Wolfpack'08 11/28/2022
@KamilCuck谢谢。我想知道的是,script.sh ./arg1 ./arg2/files.txt(这里.txt)和 pconvert -i “$file” -o “$varout/$filename_without_ext”.txt(这里.txt)没有冗余吗?
0赞 Wolfpack'08 11/28/2022
我尝试删除除 -i 和 -o 之外的所有选项,并得到“文件不存在 /ins/outs。 是确实存在的空目录。我不知道为什么我总是有奇怪的行为。它只是说“./ins/outs”不是一个目录,就好像它拒绝连接基本名称和扩展名一样,尽管运行列出的代码并试图对其进行故障排除。outs