2015-09-03 2 views
0

Я почти совершенно новый для кодирования, и я был бы признателен за обратную связь. Я пытаюсь сделать сценарий оболочки, который будет оценивать информацию в текстовом файле и перемещать указанный текстовый файл, если выполняются определенные условия. Мой код ниже:awk, bin/sh 0: 1: не найдено

#!/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 

Когда я пытаюсь запустить сценарий, я получаю эту ошибку:

[email protected]:~/Desktop/Stocks$ ./stockscript7.sh 
/bin/sh: 1: 0: not found 

я сделал, что я был в Баш оболочки. Я использовал chmod для предоставления разрешений на сценарий. В противном случае из этого сообщения об ошибке я потерял, что попробовать дальше. Любая помощь приветствуется.

+0

Вы пытались использовать '#!/usr/bin/env bash'? Может быть, bash не там, где вы думаете. Использование этой формы линии she-bang переносимо и применяется ко всем системам * nix. Однако '#!/Bin/bash' не является. Также, когда вы используете bash из терминала, вы используете 'sh' или' bash'? Существует разница, которую вы используете. – rbaleksandar

+0

Вы найдете кодирование намного проще, если вы напишете его в крошечных битах и ​​протестируете каждую модификацию вместо написания полного скрипта, а затем попытаетесь устранить ее. –

+2

EW. Использование 'system()' таким образом открывает вам серьезные уязвимости безопасности. –

ответ

3

Ниже приведен перевод на родной Баш, ни с одной из ошибок, связанных с злоупотребляя AWK, как вы (вспомните, что случилось бы с входного файла с именем EVIL'$(rm -rf .)'.txt - как созданные с помощью команды 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 в каждой строке в файле сопоставления Rank - но вы не можете успешно переместить один файл несколько раз. Возможно, вы просто хотите прочитать строку , первую строку, содержащую Rank, и переименовать файл в соответствии с номером, предшествующим тире в четвертом столбце?

#!/bin/bash 
stock=HD 
if read -r _ _ _ rating _ < <(grep -e Rank "$stock.txt") && [[ $rating ]]; then 
    mv -- "$stock.txt" ~/Desktop/Stocks/"${rating%%-*}"/ 
fi 

Объяснение:

  • <(...) заменяется именем файла, который при чтении, возвращает вывод команды прилагается. Таким образом, foo < <(...) запускает foo в родительской оболочке со своим stdin, поданным из команды в .... См. BashFAQ #24, чтобы понять, почему это необходимо, а не работает grep -e Rank "$stock.txt" | read _ _ _ rating _.
  • read _ _ _ rating _ читает четвертое слово своего входного потока в переменную rating. (Первая, вторая, третья и пятая и нижняя часть считываются в переменные с именем _, что является соглашением для чего-то, чего вас не волнует или хочет выбросить).
  • "${rating%%-*}" выбрасывает все содержимое в переменной rating следующие первой -, таким образом, преобразование 1-Strong к 1, 2-Buy к 2 и т.д.

Тем не менее, все вышесказанное не объясняет точную ошибку вы получаете. Для того, чтобы получить, что, давайте сломаем ваши awk команды:

system("mv " "'$stock'.txt" " " ~/Desktop/Stocks/1/"'$stock'.txt") ; 

... так, какие строки объединяются вместе и передаются system() (и, таким образом, /bin/sh)?

system(
    "mv " 
    "'$stock'.txt" 
    " " 
    ~/Desktop/Stocks/1/"'$stock'.txt" 
) ; 

Уточнить проблему здесь? Эта четвертая часть (которую вы собираетесь объединить вместе с остальными) не является строкой в ​​awk! Таким образом, когда он содержит операции , их обрабатывают как числовое деление - литье содержимого до него до числового значения и деление на содержимое после него (аналогично, отличное от целого). В некоторых awk-версиях, включая мои, это приводит к ошибке с делением на нуль; ваш, очевидно, отличается.

(Также $stock является буквальным строки, а не замещен HD здесь, но это отдельная тема)

0

Вы делаете вещи слишком сложными: 1) придерживаетесь только с awk и 2) повторяете имя файла в пути назначения тех команд mv.

Я предполагаю, что строка «Ранг» содержит столбцы, разделенные пробелами, и четвертый - тот, который содержит ваш идентификатор, как вы сами предполагаете. Если это или следующее предположение не выполняется, решение здесь может дать вам проблемы. См. Ответ Шарле.

Если вы уверены, что четвёртое поле всегда содержит строку с шаблоном digits-text, то вы можете попробовать с

#!/bin/bash 

stock=HD 

id=`cat "$stock.txt"|grep Rank| cut -d ' ' -f 4| sed '[email protected]*@@g'` 
echo "$stock.txt" ~/Desktop/Stocks/"$id" 
#mv "$stock.txt" ~/Desktop/Stocks/"$id" 

Я закомментирована фактической mv команды. Эхо-линия позволит вам дважды проверить, что файл действительно отправится в нужное место назначения. Сделайте несколько тестов, и если все будет выглядеть нормально, раскомментируйте строку mv, удалив знак #.

EDIT: ли убедитесь, что все каталоги ~/Desktop/Акции/$ ID существуют до выдачи команды mv. В противном случае вы потеряете эти файлы!, поскольку они перезаписывают друг друга, и только содержимое последнего файла, перемещенного в любой каталог ~/Desktop/Stocks/$ id, сохранится, но называется $ id !!

Следующий код будет следить за тем, чтобы они были перемещены в каталог и не были перезаписаны друг на друга.

#!/bin/bash 

stock=HD 
DDIR=~/Desktop/Stocks 

id=`cat "$stock.txt"|grep Rank| cut -d ' ' -f 4| sed '[email protected]*@@g'` 
echo "$stock.txt" ~/Desktop/Stocks/"$id" 
{ [ -d "$DDIR/$id" ] || mkdir "$DDIR/$id" ;} && mv "$stock.txt" ~/Desktop/Stocks/"$id" 

Это проверяет, существует ли папка $ DDIR/$ id и делает ее, если это не так. Только после этого происходит фактический ход.

+0

Бесполезное использование кошки. – Jens

+0

Также плохо багги из-за недостающих котировок. Что делать, если обрабатываемый материал имеет в названии имена пробелов или глобусов или (по какой-то причине) поле 'id' было одинаковым? –

+0

BTW, ставя окончательный '/' после '$ id', гарантирует, что это каталог, используемый в качестве адресата, и избегает случая перезаписи файлов, о которых вы беспокоитесь. Хотя вы * do * все еще нуждаетесь в большем количестве кавычек, чтобы гарантировать, что 'mv' передано только количество ожидаемых аргументов. –

2

Вы в настоящее время создания этого дерева выполнения:

shell { awk { system(shell) } } 

Не делать что это очень грязно и подвержено ошибкам. Сделайте это вместо этого (или что-то в равной степени прост):

shell { awk } 

например. это МОЖЕТ быть все, что вам нужно (в зависимости от содержимого файла HD.txt):

mv "${stock}.txt" ~/Desktop/Stocks/"$(awk '/Rank/{ sub(/-.*/,"",$4); print $4 }' "${stock}.txt")" 
+0

Я бы предложил процитировать расширение '$()', в котором вы вызываете awk - хотя бы для паранойи - но это хороший подход, о котором я не думал. (Конечно, вы также должны быть уверены, что * не *, чтобы процитировать '~', или при цитировании аргумента в целом, чтобы заменить его '$ HOME') –

+0

Если честно, я просто бросил его туда, чтобы дать OP - идея возможности. Вероятно, ему действительно нужно что-то другое, но мы не будем знать наверняка, пока не увидим его содержимое входных файлов. Я добавлю цитаты, спасибо. –

Смежные вопросы