您的第一个问题是循环中的变量赋值。

您的第一个问题是循环中的变量赋值。

我正在 Mac Automator 中创建一个服务,它基本上是一个使用 dcmodify 更改一些 dcm 文件的 bash 脚本。每当我在单个文件上运行它时,它都能完美运行,但当我尝试在整个文件夹上运行它时,它会打印一个错误

E: unable to load file [...]: No such file or directory

这是脚本,我真的不知道我可能会遗漏什么:

for f in "$@"
do
    Accession="$(/usr/bin/basename "$(/usr/bin/dirname "$f")")"
    /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0008,0050)=$Accession" "$f" -nb
    Patient="$(/usr/bin/basename "$(/usr/bin/dirname "$(/usr/bin/dirname "$f")")")"
    /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0010,0010)=$Patient" "$f" -nb
    /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0010,0020)=$Patient" "$f" -nb
done

附言:我想澄清一下,当出现错误时,它是指我想要运行的文件夹。

例如,如果我尝试在 Desktop/asd 上运行它错误信息将:

E: unable to load file /User/Desktop/asd: No such file or directory

答案1

您的第一个问题是循环中的变量赋值。

假设我有文件。我用touch file\ with\ space{001..010}.txttouch file{001..010}.txt

file with space001.txt
file with space002.txt
file with space003.txt
file with space004.txt
file with space005.txt
file with space006.txt
file with space007.txt
file with space008.txt
file with space009.txt
file with space010.txt
file001.txt
file002.txt
file003.txt
file004.txt
file005.txt
file006.txt
file007.txt
file008.txt
file009.txt
file010.txt

让我们调试你的脚本。

for f in "$@"
do
    DIRNAME="$(/usr/bin/dirname "$f")"
    BASENAME_DIRNAME="$(/usr/bin/basename "$(/usr/bin/dirname "$f")")"
    echo "$f"
    echo $DIRNAME
    echo $BASENAME_DIRNAME
done

结果是:

file with space001.txt
.
.
file with space002.txt
.
.
file with space003.txt
.
.
file with space004.txt
.
.
file with space005.txt

<ellipsis>

这就是脚本的运行方式。

+ for f in '"$@"'
/usr/bin/dirname "$f"
++ /usr/bin/dirname 'file with space001.txt'
+ DIRNAME=.
/usr/bin/basename "$(/usr/bin/dirname "$f")"
/usr/bin/dirname "$f"
+++ /usr/bin/dirname 'file with space001.txt'
++ /usr/bin/basename .
+ BASENAME_DIRNAME=.
+ echo 'file with space001.txt'
file with space001.txt
+ echo .
.
+ echo .
.
<ellipsis>

调试显示$f没有绝对路径。我相信这不是您想要的Accession变量。

要获取绝对路径,请使用realpath命令。要使用realpath,您需要通过以下方式安装 coreutilsbrew install coreutils

我建议在循环中添加这个命令。

这解决了第一个问题。

realpath的路径是/usr/local/bin/realpath。你的路径可能不同。要查找 的路径realpathwhich realpath

f=$(/usr/local/bin/realpath "$f")

for f in "$@"
do
    f=$(/usr/local/bin/realpath "$f")
    DIRNAME="$(/usr/bin/dirname "$f")"
    BASENAME_DIRNAME="$(/usr/bin/basename "$(/usr/bin/dirname "$f")")"
    echo "$f"
    echo $DIRNAME
    echo $BASENAME_DIRNAME
done

第二个问题是 Automator 中的 Zsh 不能像终端中的 Zsh 那样工作。

这是因为它们的setopt设置不同。详细的 zsh 选项解释是zsh 选项

我可以编写更简洁、更直观的脚本,但是差异setopt可能会导致错误。

因此你应该以不同的方式编写 shell 脚本。 这个差异可以修复,但是现在对于脚本来说太耗时了。

针对您的代码的建议。

#If you choose a directory.
if [[ -d $@ ]]
then
    # if you select a directory which contains files.
    for f in $@/*
    do
        f=$(/bin/realpath $f)
        /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0008,0050)=$Accession" "$f" -nb
        Patient="$(/usr/bin/basename "$(/usr/bin/dirname "$(/usr/bin/dirname "$f")")")"
        /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0010,0010)=$Patient" "$f" -nb
        /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0010,0020)=$Patient" "$f" -nb
    done
#If you don't choose directory.
else
    # if you select files.
    for f in $@
    do
        f=$(/bin/realpath $f)
        /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0008,0050)=$Accession" "$f" -nb
        Patient="$(/usr/bin/basename "$(/usr/bin/dirname "$(/usr/bin/dirname "$f")")")"
        /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0010,0010)=$Patient" "$f" -nb
        /opt/homebrew/Cellar/dcmtk/3.6.7/bin/dcmodify -m "(0010,0020)=$Patient" "$f" -nb
    done
fi

答案2

根据长期以来的 Unix 惯例,所有选项(即以一个或两个连字符开头的命令修饰符,如-v--verbose)都应放在所有位置参数(如您希望命令对其执行操作的文件名列表)之前。

因此您可能需要重写这个:

dcmodify -m "(0008,0050)=$Accession" "$f" -nb

…变成这样:

dcmodify -m "(0008,0050)=$Accession" -nb "$f"

正如您现在所看到的,dcmodify正在查找一个文件名并假设命令行的其余部分将是文件名,但它没有找到名为的文件-nb,因此它报告错误。

(您偶尔会发现不遵循此惯例的工具,但这通常表明它们是由不熟悉古老 Unix 传统的 DOS 人士从 MS-DOS 错误移植而来的。)

相关内容