Sed error "command a expects \ followed by text" - bash

Here is my script:
openscad $1 -D generate=1 -o $1.csg 2>&1 >/dev/null |
sed 's/ECHO: \"\[LC\] //' |
sed 's/"$//' |
sed '$a;' >./2d_$1
That output:
sed: 1: "$a;": command a expects \ followed by text

Your version of sed is not GNU sed which allows what you use. You need to write:
openscad $1 -D generate=1 -o $1.csg 2>&1 >/dev/null |
sed 's/ECHO: \"\[LC\] //' |
sed 's/"$//' |
sed '$a\
;' >./2d_$1
Also, three copies of sed is a little excessive (to be polite); one suffices:
openscad $1 -D generate=1 -o $1.csg 2>&1 >/dev/null |
sed -e 's/ECHO: \"\[LC\] //' \
-e 's/"$//' \
-e '$a\' \
-e ';' >./2d_$1
or:
openscad $1 -D generate=1 -o $1.csg 2>&1 >/dev/null |
sed -e 's/ECHO: \"\[LC\] //' -e 's/"$//' -e '$a\' -e ';' >./2d_$1

Related

Passing parameters to a print directory like tree command

Following an answer from Linux command to print directory structure in the form of a tree
I've got:
ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'
To list a tree directory.
Instead of just creating an alias I want it to behave like a normal command and accept parameters.
I have this directory structure:
|-myhome
|---top
|-----test
|-------folder1
|-------folder2
|-------folder3
if I want this (from "top"):
|-test
|---folder1
|---folder2
|---folder3
I have to cd top an then ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'
or, from "myhome": ls -R top | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'
I want something along the lines of:
lstree <dir>
in this case (from "top"):
lstree test
which I don't get from an alias
I'm looking into bash functions:
function ls4less(){ ls -R $1 | less}
which then I could invoke from "top"
ls4less
yielding
test
./test:
folder1
folder2
folder3
./test/folder1:
file11.txt
file12.txt
./test/folder2:
file21.txt
file22.txt
./test/folder3:
file31.txt
file32.txt
file33.txt
(END)
or
ls4less test
yielding
folder1
folder2
folder3
test/folder1:
file11.txt
file12.txt
test/folder2:
file21.txt
file22.txt
test/folder3:
file31.txt
file32.txt
file33.txt
(END)
I've got two versions:
function lstree_1(){ls -R "$1" | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'}
function lstree_2(){echo "$1" | ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'}
Enjoy

Shell script result output to a file

I just faced a problem about shell script output problem. Here is the code
read_each_user_rating(){
TOTAL_RATING_NUMBER="$(grep -c '<Author>' $1)" #Find how many rating in each file
ALL_AUTHOR="$(grep '<Author>' $1 | sed -e 's/<Author>//'| tr -d '\r')"
ALL_COMMENT="$(grep '<Content>' $1 | sed -e 's/<Content>//'| tr -d '\r')"
ALL_DATE="$(grep '<Date>' $1 | sed -e 's/<Date>//'| tr -d '\r')"
ALL_RATING_FILE="$(grep '<Overall>' $1 | sed -e 's/<Overall>//'| tr -d '\r')"
ALL_VALUE="$(grep '<Value>' $1 | sed -e 's/<Value>//'| tr -d '\r')"
ALL_ROOMS="$(grep '<Rooms>' $1 | sed -e 's/<Rooms>//'| tr -d '\r')"
ALL_LOCATION="$(grep '<Location>' $1 | sed -e 's/<Location>//'| tr -d '\r')"
ALL_CLEANLINESS="$(grep '<Cleanliness>' $1 | sed -e 's/<Cleanliness>//'| tr -d '\r')"
ALL_CHECKIN="$(grep '<Check in / front desk>' $1 | sed -e 's/<Check in / front desk>//'| tr -d '\r')"
ALL_SERVICE="$(grep '<Service>' $1 | sed -e 's/<Service>//'| tr -d '\r')"
ALL_BUSSINESS="$(grep '<Bussiness service>' $1 | sed -e 's/<Bussiness service>//'| tr -d '\r')"
for ((COUNTER_A=1;COUNTER_A<=$TOTAL_RATING_NUMBER;COUNTER_A++))
do
echo "INSERT INTO UserRating (Author,Comment,Date,Overall,Value,Rooms,Locations,Cleanliness,Checkin,Service,Bussiness)" >> hotelreviews.sql
echo $($ALL_AUTHOR | sed "${COUNTER_A}q;d") >> hotelreviews.sql
done
}
read_each_user_rating $1
I can output
echo "INSERT INTO UserRating (Author,Comment,Date,Overall,Value,Rooms,Locations,Cleanliness,Checkin,Service,Bussiness)" >> hotelreviews.sql to the file. But why i can output "echo $($ALL_AUTHOR | sed "${COUNTER_A}q;d") >> hotelreviews.sql" part to file too?
echo $($ALL_AUTHOR | sed "${COUNTER_A}q;d") >> hotelreviews.sql
is malformed. The expression inside $() must be a valid command (of which $ALL_AUTHOR is almost certainly not).
More likely you need something such as:
echo "$ALL_AUTHOR" | sed "${COUNTER_A}q;d"
inside the $().
In this case however, it's almost certainly not necessary to invoke a sub-command at all when you can simply do:
echo "$ALL_AUTHOR" | sed "${COUNTER_A}q;d" >>hotelreviews.sql

echo -e cat: argument line too long

I have bash script that would merge a huge list of text files and filter it. However I'll encounter 'argument line too long' error due to the huge list.
echo -e "`cat $dir/*.txt`" | sed '/^$/d' | grep -v "\-\-\-" | sed '/</d' | tr -d \' | tr -d '\\\/<>(){}!?~;.:+`*-_ͱ' | tr -s ' ' | sed 's/^[ \t]*//' | sort -us -o $output
I have seen some similar answers here and i know i could rectify it using find and cat the files 1st. However, i would i like to know what is the best way to run a one liner code using echo -e and cat without breaking the code and to avoid the argument line too long error. Thanks.
First, with respect to the most immediate problem: Using find ... -exec cat -- {} + or find ... -print0 | xargs -0 cat -- will prevent more arguments from being put on the command line to cat than it can handle.
The more portable (POSIX-specified) alternative to echo -e is printf '%b\n'; this is available even in configurations of bash where echo -e prints -e on output (as when the xpg_echo and posix flags are set).
However, if you use read without the -r argument, the backslashes in your input string are removed, so neither echo -e nor printf %b will be able to process them later.
Fixing this can look like:
while IFS= read -r line; do
printf '%b\n' "$line"
done \
< <(find "$dir" -name '*.txt' -exec cat -- '{}' +) \
| sed [...]
grep -v '^$' $dir/*.txt | grep -v "\-\-\-" | sed '/</d' | tr -d \' \
| tr -d '\\\/<>(){}!?~;.:+`*-_ͱ' | tr -s ' ' | sed 's/^[ \t]*//' \
| sort -us -o $output
If you think about it some more you can probably get rid of a lot more stuff and turn it into a single sed and sort, roughly:
sed -e '/^$/d' -e '/\-\-\-/d' -e '/</d' -e 's/\'\\\/<>(){}!?~;.:+`*-_ͱ//g' \
-e 's/ / /g' -e 's/^[ \t]*//' $dir/*.txt | sort -us -o $output

Bash script builds correct $cmd but fails to execute complex stream

This short script scrapes some log files daily to create a simple extract. It works from the command line and when I echo the $cmd and copy/paste, it also works. But it will breaks when I try to execute from the script itself.
I know this is a nightmare of patterns that I could probably improve, but am I missing something simple to just execute this correctly?
#!/bin/bash
priorday=$(date --date yesterday +"%Y-%m-%d")
outputfile="/home/CCHCS/da14/$priorday""_PROD_message_processing_times.txt"
cmd="grep 'Processed inbound' /home/rules/care/logs/RootLog* | cut -f5,6,12,16,18 -d\" \" | grep '^"$priorday"' | sed 's/\,/\./' | sed 's/ /\t/g' | sed -r 's/([0-9]+\-[0-9]+\-[0-9]+)\t/\1 /' | sed 's/ / /g' | sort >$outputfile"
printf "command to execute:\n"
echo $cmd
printf "\n"
$cmd
ouput:
./make_log_extract.sh command to execute: grep 'Processed inbound' /home/rules/care/logs/RootLog.log /home/rules/care/logs/RootLog.log.1
/home/rules/care/logs/RootLog.log.10
/home/rules/care/logs/RootLog.log.11
/home/rules/care/logs/RootLog.log.12
/home/rules/care/logs/RootLog.log.2
/home/rules/care/logs/RootLog.log.3
/home/rules/care/logs/RootLog.log.4
/home/rules/care/logs/RootLog.log.5
/home/rules/care/logs/RootLog.log.6
/home/rules/care/logs/RootLog.log.7
/home/rules/care/logs/RootLog.log.8
/home/rules/care/logs/RootLog.log.9 | cut -f5,6,12,16,18 -d" " | grep
'^2014-01-30' | sed 's/\,/./' | sed 's/ /\t/g' | sed -r
's/([0-9]+-[0-9]+-[0-9]+)\t/\1 /' | sed 's/ / /g' | sort
/home/CCHCS/da14/2014-01-30_PROD_message_processing_times.txt
grep: 5,6,12,16,18: No such file or directory
As grebneke comments, do not store the command and then execute it.
What you can do is to execute it but firstly print it: Bash: Print each command before executing?
priorday=$(date --date yesterday +"%Y-%m-%d")
outputfile="/home/CCHCS/da14/$priorday""_PROD_message_processing_times.txt"
set -o xtrace # <-- set printing mode "on"
grep 'Processed inbound' /home/rules/care/logs/RootLog* | cut -f5,6,12,16,18 -d\" \" | grep '^"$priorday"' | sed 's/\,/\./' | sed 's/ /\t/g' | sed -r 's/([0-9]+\-[0-9]+\-[0-9]+)\t/\1 /' | sed 's/ / /g' | sort >$outputfile"
set +o xtrace # <-- revert to normal

" echo" in bash script empty file

I have problem with echo command I need export data to csv but its empty file
#!/bin/bash
while read domain
do
ownname= whois $domain | grep -A 1 -i "Administrative Contact:" |cut -d ":" -f 2 | sed 's/ //' | sed -e :a -e '$!N;s/ \n/,/;ta'
echo -e "$ownname" >> test.csv
done < dom.txt
You need to use command substitution to store command's output in a shell variable:
#!/bin/bash
while read domain; do
ownname=$(whois $domain | grep -A 1 -i "Administrative Contact:" |cut -d ":" -f 2 | sed 's/ //' | sed -e :a -e '$!N;s/ \n/,/;ta')
echo -e "$ownname" >> test.csv
done
PS: I haven't tested all the piped commands.

Resources