我对编码几乎是全新的,我会很感激反馈。我正在尝试制作一个shell脚本,它将评估文本文件中的信息,并在满足某些条件时移动所述文本文件。我的代码如下:
#!/bin/bash
stock=HD
awk ' /Rank/ {
if ( $4 == "1-Strong" ) system("mv " "'$stock'.txt" " " ~/Desktop/Stocks/1/"'$stock'.txt") ;
else if ( $4 == "2-Buy" ) system("mv " "'$stock'.txt" " " ~/Desktop/Stocks/2/"'$stock'.txt") ;
else if ( $4 == "3-Hold" ) system("mv " "'$stock'.txt" " " ~/Desktop/Stocks/3/"'$stock'.txt") ;
else if ( $4 == "4-Sell" ) system("mv " "'$stock'.txt" " " ~/Desktop/Stocks/4/"'$stock'.txt") ;
else if ( $4 == "5-Strong" ) system("mv " "'$stock'.txt" " " ~/Desktop/Stocks/5/"'$stock'.txt")
} ' $stock.txt
当我尝试运行脚本时,出现此错误:
andrew@andrew-VirtualBox:~/Desktop/Stocks$ ./stockscript7.sh
/bin/sh: 1: 0: not found
我确定我在bash shell中。我确实使用chmod来赋予脚本权限。否则,从这个错误消息我失去了下一步尝试。任何帮助将不胜感激。
答案 0 :(得分:3)
以下是对本机bash的翻译,没有任何与滥用awk相关的错误(考虑使用名为EVIL'$(rm -rf .)'.txt
的输入文件会发生什么 - 使用命令{{1创建}}):
touch $'EVIL\'$(rm -rf .)\'.txt'
然而,这并没有多大意义,因为它写了:你在匹配#!/bin/bash
stock=HD
while IFS= read -r line; do
[[ $line = *Rank* ]] || continue
read -r _ _ _ rank _ <<<"$line"
case $rank in
1-Strong) mv -- "$stock.txt" ~/Desktop/Stocks/1/ ;;
2-Buy) mv -- "$stock.txt" ~/Desktop/Stocks/2/ ;;
3-Hold) mv -- "$stock.txt" ~/Desktop/Stocks/3/ ;;
4-Sell) mv -- "$stock.txt" ~/Desktop/Stocks/4/ ;;
5-Strong) mv -- "$stock.txt" ~/Desktop/Stocks/5/ ;;
esac
done <"$stock.txt"
的文件中每行运行一个mv
- 但你可以& #39; t多次成功移动单个文件。也许您只想阅读包含Rank
的第一个行,并根据第四列中的短划线前面的数字重命名该文件?
Rank
说明:
#!/bin/bash
stock=HD
if read -r _ _ _ rating _ < <(grep -e Rank "$stock.txt") && [[ $rating ]]; then
mv -- "$stock.txt" ~/Desktop/Stocks/"${rating%%-*}"/
fi
将替换为文件名,当读取该文件名时,将返回所包含命令的输出。因此,<(...)
在父shell中运行foo < <(...)
,其stdin来自foo
中的命令。请参阅BashFAQ #24以了解为什么这是必要的,而不是运行...
。grep -e Rank "$stock.txt" | read _ _ _ rating _
将其输入流的第四个字读入变量read _ _ _ rating _
。 (第一个,第二个,第三个,第五个和第五个被读入名为rating
的变量,这是你不关心/想要扔掉的东西的惯例。_
会在第一个"${rating%%-*}"
之后抛弃变量rating
中的所有内容,从而将-
转换为1-Strong
,1
转换为{ {1}}等等。但是,以上所有内容并未解释您收到的确切错误。为此,让我们分解您的2-Buy
命令:
2
...那么,串联在一起并传递给awk
的字符串是什么(因此system("mv " "'$stock'.txt" " " ~/Desktop/Stocks/1/"'$stock'.txt") ;
)?
system()
在这里查看问题?第四件(你打算和其他人连在一起)不是awk中的一个字符串!因此,当它包含/bin/sh
次操作时,将其视为数字除法 - 将之前的内容转换为数值,然后除以其后的内容(同样转换为整数) 。在某些awk版本中,包括我的版本,这会导致零除错误;你的显然不同。
(另外,system(
"mv "
"'$stock'.txt"
" "
~/Desktop/Stocks/1/"'$stock'.txt"
) ;
是文字字符串,此处未用/
替换,但这是一个单独的问题)
答案 1 :(得分:2)
您当前正在创建此执行树:
shell { awk { system( shell ) } }
不要这样做,它非常混乱且容易出错。这样做(或同样简单):
shell { awk }
e.g。这可能是您所需要的(取决于HD.txt的内容):
mv "${stock}.txt" ~/Desktop/Stocks/"$(awk '/Rank/{ sub(/-.*/,"",$4); print $4 }' "${stock}.txt")"
答案 2 :(得分:0)
你把事情弄得太复杂了1)坚持使用awk和2)在那些mv
命令的目标路径中重复文件名。
我将假设&#34; Rank&#34; line有以空格分隔的列,第4个是包含你的id的列,正如你自己所假设的那样。 如果此假设或以下假设不成立,则此处的解决方案可能会给您带来问题。见查理的回答。
如果您确定第4个字段始终包含格式为digits-text
的字符串,那么您可以尝试使用
#!/bin/bash
stock=HD
id=`cat "$stock.txt"|grep Rank| cut -d ' ' -f 4| sed 's@-.*@@g'`
echo "$stock.txt" ~/Desktop/Stocks/"$id"
#mv "$stock.txt" ~/Desktop/Stocks/"$id"
我已经注释掉了实际的mv
命令。回声线将允许您仔细检查文件是否确实会到达正确的目的地。进行一些测试,如果事情看起来不错,请通过删除符号mv
取消注释#
行。
编辑:确保所有目录〜/ Desktop / Stocks / $ id在发出mv
命令之前存在。否则你将丢失这些文件!,因为它们会相互覆盖,只有移动到任何给定〜/ Desktop / Stocks / $ id目录的最后一个文件的内容才能生存 - 但是命名$ ID !!
以下代码将确保将它们移动到目录中并且不会相互覆盖。
#!/bin/bash
stock=HD
DDIR=~/Desktop/Stocks
id=`cat "$stock.txt"|grep Rank| cut -d ' ' -f 4| sed 's@-.*@@g'`
echo "$stock.txt" ~/Desktop/Stocks/"$id"
{ [ -d "$DDIR/$id" ] || mkdir "$DDIR/$id" ;} && mv "$stock.txt" ~/Desktop/Stocks/"$id"
首先检查文件夹$ DDIR / $ id是否存在,如果它不存在则进行检查。只有这样才能继续实际行动。