我正在尝试替换在 AIX 中不起作用的特定字符串,但当我在 RHEL 上运行它时,我能够获得预期的输出。
这是命令:
filename=25_032021_abcdefghijklmn.txt; mv /u/foo/test/25_032021_test_${filename:10:14}.txt /u/foo/test/25_032021_test_${filename:10:14}.txt.tmpExtension
这是我在 AIX 上运行此命令时遇到的错误
ksh: /u/foo/test/25_032021_test_${filename:10:14}.txt: 0403-011 The specified substitution is not valid for this command.
知道我可能做错了什么吗?
答案1
${param:offset:length}
是由 ¹ 引入的ksh93
,它在 中不可用ksh88
。因此,您需要确保该脚本由 ksh93 解释,而不是 ksh88。
还要记住,在大多数类似 Bourne 的 shell 中,至少在列表上下文中,参数扩展必须被引用。
您可以在启用行编辑器的交互中键入Esc, Ctrl+ (在或 或后面)来检查其版本。Vksh
set -o emacs
vi
gmacs
在这里,${filename:10:14}
您可以使用
filename=25_032021_abcdefghijklmn.txt
id="${filename%.*}" # remove extension from the end
id="${id#*_*_}" # remove up to second _ from the start
mv "/u/foo/test/25_032021_test_$id.txt" \
"/u/foo/test/25_032021_test_$id.txt.tmpExtension"
要从开头删除 10 个字符而不是*_*_
,请使用${param#??????????}
。因此,假设id=${filename:10:14}
至少filename
有 24 个字符,则相当于:
id=${filename#??????????} # remove 10 characters from the start
id=${id%"${id#??????????????}"} # remove from the end: $id stripped of
# its first 14 characters
这些${param#pattern}
和${param%pattern}
是在 的早期版本中引入的ksh
(已经在 ksh85 中),甚至由 POSIX for 指定,因此您应该在任何时候或现在sh
都能找到它们。sh
ksh
或者,您也可以走前克什时代的古老道路,诉诸expr
²。
id=`expr "x$filename" : 'x.\{10\}\(.\{14\}\)'`
或者:
id=`expr "x$filename" : 'x.\{10\}\(.\{0,14\}\)'`
${filename:10:14}
(当$filename
字符数少于 24 个时,与 ksh93 的更严格等效)。
请注意,expr
如果它输出的是数字 0 或空字符串的表示或正则表达式不匹配,则会返回失败退出状态,因此|| true
如果启用了该errexit
选项,则可能需要附加 a ,因此它不会123456789_00000000000000.txt
例如,导致 shell 在调用的文件上退出。
如果expr
ID以换行符结尾(该换行符将被命令替换删除)。
1bash
自 2.0(1996 年底)、mksh
自 R30(2007)和zsh
自 4.3.11(2010 年底)以来也可用,但自 1991 年的 2.0 起zsh
就有$param[first,last]
。
² 虽然\{n,m\}
regexp 运算符如今已成为标准操作符,但在 ksh 出现之前的那些日子里,它是不可用的,并且您必须使用例如.\{10\}
替换。..........