我正在尝试创建一个脚本,该脚本可以:
- 查找名称包含“foobar”的文件
- 在此文件上执行脚本,输出必须存储在新的 CSV 文件中,该文件是自动创建的,并且与搜索的文件同名。唯一的区别是扩展名更改为 CSV。
这是我的剧本。 :
#!/bin/bash
# search for file containing "foobar" as a name in the directory
for file in /home/user/Documents/* ;
do
if [[ "$file" == *"$foobar"* ]]; then
touch /home/user/Documents/collectCSV/csv1.csv
# executing script of modelising foobar file ==> extract some data from $foobar file and insert it in the
# created file csv1.csv
/home/user/scriptModelise.pl $file >> /home/user/Documents/collectCSV/csv1.csv
else
echo "foobar file not found"
fi
done
问题是这种创建文件的方法是静态的。我没有成功地自动创建文件。我的意思是,当它找到 foobar 文件时,它将在将创建的新文件中进行建模。
有什么帮助吗?
答案1
更容易使用(请注意,当您像这样不加引号的变量时,zsh
您已经在使用语法):zsh
#! /bin/zsh -
files=(/home/user/Documents/*foobar*(N))
if (($#files)) {
ret=0
for f ($files) {
/home/user/scriptModelise.pl $f > $f:h/collectCSV/$f:t:r.csv || ret=$?
}
exit $ret
} else {
echo >&2 No non-hidden foobar file
exit 1
}
- 就像在 中一样
csh
,$f:h
是头(dirname),$f:t
尾部(basename),$f:r
根(删除扩展名)。 ((arithmetic expression))
就像ksh
评估算术表达式如果解析为非零值则返回 true。$#array
,让人想起ksh
s${#string}
给出数组的长度(以元素数量表示)。在ksh
/bash
中,数组并不是真正不同的类型,您需要${#array[@]}
索引${#array}
0 的元素的长度(以字符数为单位)。(N)
: glob 限定符,表示如果没有匹配则扩展为空$f
,$files
:与其他类似 Bourne 的 shell 相反,变量不需要用引号引起来(只要它们不包含空值)。在其他 shell(ksh、bash、yash)中,您需要"$f"
和"${files[@]}"
。
答案2
尝试
for file in *"$foobar"*
do
dest="$(echo $file| sed -e 's/\(.*\)\.[^\.]*$/\1.csv/' )"
if test -f "$file"
then
/home/user/scriptModelise.pl "$file" >> /home/user/Documents/collectCSV/$dest
else
echo "no $foobar file"
fi
done
在哪里
\(.*\)\.[^\.]*$
捕获具有任何字符的模式,(模式结尾)后跟一个点,非点直到行尾\1.csv
插入找到的模式,添加 .csv*"$foobar"*
*foobar*
如果没有找到匹配的文件,将扩展为字面量(具有正确的值)。因此需要test -f "$file"
编辑:
\(.*\)\.[^\.]*$
(左侧:寻找模式)
分成( _ 是占位符)
__.*__________
具有任何字符的模式(点具有特殊含义:任何字符)__.*__\._______
带有任何字符的模式,后跟一个点(转义点是普通点)__.*__\.[^\.]*$
具有任何字符的模式,(模式结尾)后跟一个点,非点 ([^\.]*
) 直到行尾(美元符号对于行尾是特殊的)\(__\)__________
捕获模式的第一部分。\1.csv
(右手边,做什么)\1____
\1
\( \)
匹配第一个、\2
第二个等中的内容,用于&
整个模式。
答案3
使用 GNU Parallel 可以轻松做到这一点,并且可以一次处理多个文件作为奖励:
parallel /home/user/scriptModelise.pl {} ">>" {.}.csv ::: *"$foobar"*
如果没有文件匹配,这将导致错误*"$foobar"*
,因此您应该首先检查这一点,或者使用find
管道输入名称,或者设置 bash 的failglob
选项。