I want to cat the lines of a csv file using "cat ~/Desktop/file.csv" in a loop using an input user path and when I execute this command in the terminal it works but not with the loop.
When I execute this script it works perfect :
for line in $(cat ~/Desktop/file.csv);
do echo $line;
done
I execute a small script in my desk by clicking on an icon : algo.command and I enter this path : ~/Desktop/file.csv
my script is :
read -p "Enter the path of your file :" path
for line in $(cat "$path");
do echo $line;
done
and I have this output :
cat: ~/Desktop/file.csv: No such file or directory
[Process completed]
Thank you for your help
The ~ is not replaced by /home/<your login name> as you expected because you read a string and you get it as it is, the shell does not interpret it like in your working case.
You have to give the path without using ~ except if you do the substitution in the script by yourself :
If your script is executed by bash :
read -p "Enter the path of your file :" path
if [ ${path:0:2} = "~/" ]
then
path=${path/\~/$HOME}
elif [ ${path:0:1} = "~" ]
then
# suppose ~<user name>
path=${path/\~/\/home\/}
fi
for line in $(cat "$path");
do echo $line;
done
Example having that script in /tmp/s
pi#raspberrypi:/tmp $ echo ~
/home/pi
pi#raspberrypi:/tmp $ (echo aze ; echo qsd) > ~/aze
pi#raspberrypi:/tmp $ cat ~/aze
aze
qsd
pi#raspberrypi:/tmp $ bash s
Enter the path of your file :~/aze
aze
qsd
pi#raspberrypi:/tmp $ bash s
Enter the path of your file :~pi/aze
aze
qsd
pi#raspberrypi:/tmp $ cd
pi#raspberrypi:~ $ bash /tmp/s
Enter the path of your file :aze
aze
qsd
pi#raspberrypi:~ $
Related
i am trying to read commands from the json file using jq.
Although i am able to read content as per requirement but only issue currently facing is that after getting values from json array each string value is automatically getting split a space which is dividing content of string into n no of values instead of one.
JSON FILE
{
"baseVersion": "abc",
"patches": [{
"version": "122",
"description": "This patch contains fixes blah blah blah ",
"iBuild": "60",
"files": [{
"fullPath": "20.6.I60.jar",
"nodeTypes": [
"a",
"b"
],
"productTypes": ["a", "b"],
"restart": "true",
"service_commands": [{
"node_name": ["a"],
"command": ["ls","date","demo"]
},{
"node_name": ["b"],
"command": ["singleline command00"]
}]
}]
}]}
Code to read content
#!/bin/bash
trap 'Exit 1' INT TERM
umask 022
getServiceRestartForNode()
{
local patchConfFile="/pathto/patch_conf.json"
local query='.patches[] | .version as $v'
query+=' | .files[] | .service_commands[] |.command[]'
local outputCommands=($(jq -cr "$query" "$patchConfFile"))
local result=${PIPESTATUS[0]}
if [ "$result" -ne 0 ]
then
Display -e "ERROR: Error listing files (error code: '$result')"
return 1
else
echo "${outputCommands[#]}"
for servicecommand in "${outputCommands[#]}"
do
"$servicecommand"
# if [[ "$?" -ne 0 ]]
# then
# display "0" "command $servicecommand failed."
# fi
done
fi
return 0
}
if [[ $1 = "-o" ]]; then
echo "Option -o turned on"
getServiceRestartForNode
else
echo "You did not use option -o"
fi
Current output
Option -o turned on
ls date demo singleline command
a.out demo.sh patch_conf.json
Wed Jun 2 16:29:23 IST 2021
demo.sh: line 26: demo: command not found
demo.sh: line 26: singleline : command not found
Expected output
Option -o turned on
ls date demo singleline command00
a.out demo.sh patch_conf.json
Wed Jun 2 16:29:23 IST 2021
demo.sh: line 26: demo : command not found
demo.sh: line 26: singleline command00 : command not found
The last executed "singleline", But it was supposed to be "singleline command".
Thank you in advance
Replace these lines:
local outputCommands=($(jq -cr "$query" "$patchConfFile"))
local result=${PIPESTATUS[0]}
with these lines:
outputCommands=()
while IFS='' read -r line || ! result=$line; do outputCommands+=("$line"); done < <(jq -r "$query" "$patchConfFile"; echo -n $?)
and you should be good to go.
In the JQ command, I'm ditching the -c option so that the results print one per line. Then I'm using BASH's read to read in the lines one at a time, populating the array with each line (thereby eliminating the word-splitting on the space in the "singleline command00" command). The <(jq ...) bit is called "process substitution", and it allows the script to read the output of a process as if it were a file. And finally, the || ! result=$line and ; echo -n $? combine to allow proper error checking within the process substitution.
Using an echo in place of actually executing the command, the output looks like this:
</tmp> $ ./so3428.sh -o
Option -o turned on
ls date demo singleline command00
CMD <ls>
CMD <date>
CMD <demo>
CMD <singleline command00>
If I mangle the name of the file to generate a JQ error, I get:
</tmp> $ ./so3428.sh -o
Option -o turned on
jq: error: Could not open file x/tmp/so3428.json: No such file or directory
./so3428.sh: line 18: Display: command not found
There's more that could be cleaned up in here, but I'll point you to shellcheck for that.
I'm new to C language so please don't be harsh on me. I want to run a program this way : ./test -option 3,2 < text.txt
I want to execute the program regardless of the file exists or not.
So that ./test -option 3,4,2 < text.txt is the same as ./test -option 3,4,2
without
getting the message *-bash: hehe: No such file or directory*
Thanks
You can use a ternary:
[ -f test.txt ] && ./test -option 3,2 < test.txt || echo "" | ./test -option 3,2
In order to avoid repeating the command, you can also use:
CMD="./test -option 3,2"; [ -f test.txt ] && $CMD < test.txt || echo "" | $CMD
Also, notice that test is a command, consider using another name for your program.
The user will give any amount of positional parameters that they want (which are all C programs). I want to make it so that all of the C programs compile. However this is not working; does anyone have a solution?
echo '#!/bin/bash' >> compile
echo if [ "-o"='$1' ] >> compile
echo then >> compile
echo for (i=3; i<='$#'; i++) >> compile
echo do >> compile
echo gcc -o '$2' '${i}' >> compile
echo fi >> compile
Don't use a bunch of echo statements, use a here-doc. Putting quotes around the token after << prevents expanding variables inside the here-doc.
cat <<'EOF' >>compile
'#!/bin/bash'
if [ "-o" = "$1" ]
then
for ((i=3; i <= $#; i++))
do
gcc -o "$2" "${!i}"
done
fi
EOF
Otherwise, you need to escape or quote all the special characters -- you were getting an error because you didn't escape the < in the for() line.
Other mistakes: you need spaces around = in the [ command, and you were missing done at the end of the for loop. And to access a variable indirectly, you need to use ${!var} syntax.
The usual way to iterate over all the arguments is with a simple:
for arg
loop. When there's no in after for variable, it loops over the arguments. You just need to remove the -o outputfile argument first:
output=$2
shift 2 # remove first 2 arguments
for arg
do
gcc -o "$output" "$arg"
done
Here is how I would edit what you originally posted:
$ cat test.sh
echo -e "#!/bin/bash" > compile.sh
echo -e "if [ \"\${1}\" == \"-o\" ]; then" >> compile.sh
echo -e "\tlist_of_arguments=\${#:3} #puts all arguments starting with \$3 into one argument" >> compile.sh
echo -e "\tfor i in \${list_of_arguments}; do" >> compile.sh
echo -e "\t\techo \"gcc \${1} '\${2}' '\${i}'\"" >> compile.sh
echo -e "\tdone" >> compile.sh
echo -e "fi" >> compile.sh
$ ./test.sh
$ cat compile.sh
#!/bin/bash
if [ "${1}" == "-o" ]; then
list_of_arguments=${#:3} #puts all arguments starting with $3 into one argument
for i in ${list_of_arguments}; do
echo "gcc ${1} '${2}' '${i}'"
done
fi
$ chmod +x compile.sh
$ ./compile.sh -o one two three four five
gcc -o 'one' 'two'
gcc -o 'one' 'three'
gcc -o 'one' 'four'
gcc -o 'one' 'five'
for demonstration purposed, I echoed the gcc command in test.sh. To actually run gcc instead of echoing it, change line five in test.sh from:
echo -e "\t\techo \"gcc \${1} '\${2}' '\${i}'\"" >> compile.sh
to
echo -e "\t\tgcc \${1} '\${2}' '\${i}'" >> compile.sh
or pipe the echo to sh like so:
echo -e "\t\techo \"gcc \${1} '\${2}' '\${i}'\" \| sh" >> compile.sh
Requirement :
Able to send a file containing numbers (433 434 435) as a parameter
sh Test.sh myFile.txt
Parameters can be numbers directly if not a file (433 434 434)
sh Test.sh 434 435 436
So , it has to support both file and numbers as the parameters
Below is the code i ve tried writing but in the for loop below , all numbers are getting printed as a string , but i need the for loop to run thrice as the input values are 3.
How to have it as a part of an array in shell script
Iam relatively new to shell script
OutPut:
In either case for loop has to run the number of parameter times(filedata determinies the parameters or direct input)
Please advice if any unforeseen bugs exist
#!/bin/bash
echo -e $# 2>&1 ;
myFile=$1 ; // As the first parameter will be a file
#[ -f "$myFile" ] && echo "$myFile Found" || echo "$myFile Not found"
if [ -f "$myFile" ]; then
tcId=`cat $#`;
echo $tcId;
else
tcId=$#;
echo $tcId;
fi
# Execute each of the given tests
for testCase in "$tcId"
do
echo "Test Case is "$testCase ;
done
I'd use a process substitution to "pretend" the explicit arguments are in a file.
while IFS= read -r testCase; do
echo "Test case is $testCase"
done < <( if [ -f "$1" ]; then
cat "$1"
else
printf "%s\n" "$#"
fi
)
If you are flexible in how your script is called, I would simplify it to only read test cases from standard input
while IFS= read -r testCase; do
echo "Test case is $testCase"
done
and call it one of two ways, neither using command line arguments:
sh Test.sh < myFile.txt
or
sh Test.sh <<TESTCASES
433
434
434
TESTCASES
I am reading in a small csv file in the format size,name - one set per line. For my testing file I have two lines in the csv file.
If I use the code
while
IFS=',' read -r size name
do
printf "%s\n" "name"
done < temp1.txt
The name values for each of the lines is printed to the terminal.
If I use the code
while
IFS=',' read -r size name
do
printf "%s\n" "name" > temp2.txt
done < temp1.txt
Then only the last name is printed to the temp2.txt file.
What am I doing wrong?!
You are using >, so that the file gets truncated every time. Instead, use >> to append:
So it should be like this:
printf "%s\n" "name" >> temp2.txt
^^
All together:
while
IFS=',' read -r size name
do
printf "%s\n" "name" >> temp2.txt
done < temp1.txt
Basic example:
$ echo "hello" > a
$ echo "bye" > a
$ cat a
bye # just last line gets written
$ echo "hello" >> a
$ echo "bye" >> a
$ cat a
hello
bye # everything gets written