这是我的文字档案:
└─ $ ▶ cat myfile.txt
$FLD,abc
$FLD,xyz
$TRA,yyt
这是我的环境变量:
└─ $ ▶ echo $FLD
/Users
└─ $ ▶ echo $TRA
/opt
我想要做的是从文件中获取环境变量本身,然后将目录更改为该目录,并在文件的第2列中执行命令。
└─ $ ▶ cat myscript.sh
IFS=","
while read f1 f2
do
target_folder=`echo $f1`
target_path=$f2
echo "It is going to be executed $target_path file in $target_folder folder"
cd $target_folder
done < myfile.txt
由于美元符号自动转义,我无法更改文件夹并收到此错误:
└─ $ ▶ sh myscript.sh
It is going to be executed abc file in $FLD folder
myscript.sh: line 7: cd: $FLD: No such file or directory
It is going to be executed xyz file in $FLD folder
myscript.sh: line 7: cd: $FLD: No such file or directory
It is going to be executed yyt file in $TRA folder
myscript.sh: line 7: cd: $TRA: No such file or directory
这种情况类似:
└─ $ ▶ var1=$FLD
└─ $ ▶ var2=\$FLD
└─ $ ▶ cd $var1
└─ $ ▶ cd $var2
-bash: cd: $FLD: No such file or directory
感谢您的帮助。
答案 0 :(得分:1)
虽然原则上使用 eval
,但出于安全原因,通常应避免使用。
例如,您的文件的第1列可以包含任意命令 eval
然后盲目执行。
根据您问题中的错误消息,我推断您使用bash
,这允许使用与运算符=~
的扩展正则表达式匹配和间接变量扩展获得强大而安全的解决方案:
while IFS=',' read -r f1 f2
do
target_folder=$f1
# Only try to expand the value if it starts with '$' and is followed by
# a legal variable name, and nothing else.
if [[ $target_folder =~ ^\$([_a-zA-Z][a-zA-Z0-9]*)$ ]]; then
# Use variable indirection to get the variable's value.
vname=${BASH_REMATCH[1]}
target_folder=${!vname}
fi
target_path=$f2
echo "Executing file $target_path in folder $target_folder..."
cd "$target_folder"
done < myfile.txt
请注意,Bash的variable indirection仍为allows injection of arbitrary commands,通过数组索引,因此需要首先测试$target_folder
的值。
另请注意在IFS=','
命令之前直接使用read
,该命令将更改范围限定为该命令,而不会全局更改$IFS
的值。
此外,-r
几乎总是与read
一起使用的正确选项,以防止对\
字符的意外解释。在输入中。
符合POSIX的解决方案也是可能的,但在这种情况下,它需要使用外部实用程序来测试有效的变量名称sed
:
while IFS=',' read -r f1 f2
do
target_folder=$f1
# Only try to expand the value if it is '$' followed by
# a legal variable name, and nothing else.
if [ -n "$(printf %s "$target_folder" | sed -n '/^\$[_a-zA-Z][a-zA-Z0-9]*$/p')" ]; then
# Given that we've ensured that $target_folder contains a valid variable reference,
# we can now use `eval` safely.
target_folder=$(eval "printf %s \"$target_folder\"")
fi
target_path=$f2
echo "Executing file $target_path in folder $target_folder..."
cd "$target_folder"
done < < myfile.txt
请注意,即使使用eval
(变量间接不是POSIX shell规范的一部分),在这种情况下它的使用是安全的,因为我们确保要评估的字符串是只是一个变量引用。
答案 1 :(得分:0)
试试这个:
IFS=","
while read f1 f2
do
target_folder=$f1
target_path=$f2
eval "cd "$target_folder
done < myfile.txt