Ambiguous redirect error bash [duplicate] - bash

This question already has answers here:
Getting an "ambiguous redirect" error
(14 answers)
Closed 5 years ago.
There have been other posts regarding this problem, but none answer my question.The other posts mention adding quotes, but that leads to an EOF while matchign error.
I am writing a bash script that contains the following line, but when I execute, I get an error message which reads "Ambiguous redirect." Why?
done < $(cat $textfile1 $textfile2) >> $outputfile

At barest minimum, you need more quotes.
# PROBABLY NOT WHAT YOU WANT:
# Read from an input file whose name is generated by concatenating the contents of the
# files named in textfile1 and textfile2 variables
done < "$(cat -- "$textfile1" "$textfile2")" >>"$outputfile"
Assuming you want to read from a stream that consists of textfile1 and textfile2 concatenated (rather than from a file with a name that consists of those), this should be:
# PRESUMABLY CORRECT:
# Read from a stream with the contents of textfile1 and then textfile2
done < <(cat -- "$textfile1" "$textfile2") >>"$outputfile"

Related

Why isn't my while loop working through scp when reiterating through a list [duplicate]

This question already has answers here:
Filename not printing correctly with underscore "_" in Bash [duplicate]
(2 answers)
Closed 3 years ago.
Hi I am trying to transfer a list of files from the server to my computer using a while loop, but it keeps giving me the error that there is no file or directory. I can't understand why.
So I have this file list_numbers.txt with over 500 lines
list_numbers.txt
1234
345
2135
2132
...
And I want to re-iterate through this list to transfer files from server to my computer with the corresponding foldername to my computer but replacing assembly_graph.txt with $line_for_assembly.txt
while read line; do scp -r user#server.com:/home/Documents/$line_assembly/assembly_graph.txt /Users/Documents/$line_for_assembly.txt; done < list_numbers.txt
So basically I want it to do the below code, but instead of me having to manually type it, it would re-iterate through the list.
scp -r user#server.com:/home/Documents/1234_assembly/assembly_graph.txt /Users/Documents/1234_for_assembly.txt
scp -r user#server.com:/home/Documents/345_assembly/assembly_graph.txt /Users/Documents/345_for_assembly.txt
scp -r user#server.com:/home/Documents/2135_assembly/assembly_graph.txt /Users/Documents/2135_for_assembly.txt
scp -r user#server.com:/home/Documents/2132_assembly/assembly_graph.txt /Users/Documents/2132_for_assembly.txt
But I get this error:
scp: /home/Documents//assembly_graph.txt: No such file or directory
So it is not picking up the $line_assembly, even when I do ${line}_assembly. I don't know what I'm doing wrong.
because you do not have a variable named line_assembly.
Perhaps you mean to the following:
while read line
do
line=`echo $line | tr -d '\r\n'`
scp -r user#server.com:/home/Documents/${line}_assembly/assembly_graph.txt /Users/Documents/${line}_for_assembly.txt
done < list_numbers.txt
this will expand as the value of line followed by the text "_assembly".
For example if "line" has the value "component" you will get
.../Documents/component_assembly/...
EDIT: OP had spurious characters in his/her input file (probably \r characters from windows). I've edited the answer accordingly to accommodate OP's specific issue.

Passing sequential list to for loop [duplicate]

This question already has answers here:
How do I iterate over a range of numbers defined by variables in Bash?
(20 answers)
Closed 4 years ago.
I have a list of files to put through a for loop. They are named
FA2_00032.png, FA2_00033.png, etc
I have variables $imID which contains FA2 string, $startFrame which contains the start frame (e.g. 00034) and $endFrame which contains to end frame (e.g. 00894).
I have managed to get the list of relevant files using:
eval echo ${imageID}_{${startFrame}..${endFrame}}.png;
This outputs
FA2_00034 FA2_00035 FA2_00036 etc
But now I need to pass this to the for loop. That is,
for file in *the above list*
where *the above list* is the block quoted list above. $file should contain FA2_00034, FA2_00035, etc for use in the for loop.
Use a C-style for loop, not eval+{...}, for tasks like this. printf can be used to assemble the file name from the current integer. The syntax 10#$foo ensures that the value of $foo is treated as a decimal (not an octal) number if it includes leading 0s.
imageID=FA2
startFrame=00034
endFrame=00894
for ((i=10#startFrame; i<=10#$endFrame; i++)); do
printf -v file '%s_%05d.png' "$imageID" "$i"
echo "Operating on $file" >&2
done

Bash for loop and glob expansion [duplicate]

This question already has answers here:
Looping on empty directory content in Bash [duplicate]
(2 answers)
Closed 7 years ago.
Consider the following bash code:
for f in /tmp/*.dat; do echo ${f}; done
when I run this and there is no *.dat file in /tmp the output is:
/tmp/*.dat
which is clearly not what I want. However, when there is such a file, it will print out the correct one
/tmp/foo.dat
How can I force the for loop to return 'nothing' when there is no such file in the directory. The find-command is not an option, sorry for that :/ I would like to have also a solution without testing, if *.dat is a file or not. Any solutions so far?
This should work:
shopt -s nullglob
...
From Bash Manual
nullglob
If set, Bash allows filename patterns which match no files to expand
to a null string, rather than themselves.

for loop on files that don't exist [duplicate]

This question already has answers here:
How to skip the for loop when there are no matching files?
(2 answers)
Closed 3 years ago.
I want to process a set of files (*.ui) in the current directory. The following script works as expected if some *.ui files are found. But if no .ui file exist the current directory, the for loop is entered all the same. Why is that ?
for f in *.ui
do
echo "Processing $f..."
done
It prints :
Processing *.ui...
Use:
shopt -s nullglob
From man bash:
nullglob
If set, bash allows patterns which match no files (see Pathname Expansion
above) to expand to a null string, rather than themselves.
You already have the how, the 'why' is that bash will first try to match *.ui to files, but if that doesn't work (it gets no results) it will assume you meant the string "*.ui".
for f in "*.ui"
do
echo "Processing $f..."
done
wil indeed print "Processing *.ui".

bash script error possibly related to length of filename (actually I don't know what's wrong) [duplicate]

This question already has answers here:
Are shell scripts sensitive to encoding and line endings?
(14 answers)
Closed 5 years ago.
Here's an example of my problematic code:
#!/bin/bash
fileList='fileList.txt'
#IFS=$'\n'
while read filename
do
echo listing "$filename"
ls -ligG "$filename"
done < "$fileList"
echo "done."
#unset IFS
exit 0
The output is:
listing /some/long/path/README.TXT
ls: cannot access /some/long/pa
: No such file or directoryDME.TXT
Notice that ls cuts off the path. Also notice that the end of the path/filename is appended to the error message (after "No such file or directory").
I just tested it with a path exactly this long and it still gives the error:
/this/is/an/example/of/shorter/name.txt
Anyone know what's going on? I've been messing with this for hours already :-/
In response to torek's answer, here is more info:
First, here's the modified script based on torek's suggestions:
#!/bin/bash
fileList=/settings/Scripts/fileList.txt
while IFS=$'\n' read -r filename
do
printf 'listing %q\n' "$filename"
ls -ligG $filename
done < "$fileList"
echo "done."
exit 0
Here's the output of that:
# ./test.sh
listing $'/example/pathname/myfile.txt\r'
: No such file or directorypathname/myfile.txt
done.
Notice there is some craziness going on still.
Here's the file. It does exist.
ls -ligG /example/pathname/myfile.txt
106828 -rwxrwx--- 1 34 Mar 28 00:55 /example/pathname/myfile.txt
Based on the unusual behavior, I'm going to say the file has CRLF line terminators. Your file names actually have an invisible carriage return appended to the name. In echo, this doesn't show up, since it just jumps to the first column then prints a newline. However, ls tries to access the file including the hidden carriage return, and in its error message, the carriage return causes the error message partially overwrite your path.
To trim these chars away, you can use tr:
tr -d '\r' < fileList.txt > fileListTrimmed.txt
and try using that file instead.
That embedded newline is a clue: the error message should read ls: cannot access /some/long/path/README.TXT: No such file or directory (no newline after the "a" in "path"). Even if there were some mysterious truncation happening, the colon should happen right after the "a" in "path". It doesn't, so, the string is not what it seems to be.
Try:
printf 'listing %q\n' "$filename"
for printing the file name before invoking ls. Bash's built-in printf has a %q format that will quote funny characters.
I'm not sure what the intent of the commented-out IFS-setting is. Perhaps you want to prevent read from splitting at whitespace? You can put the IFS= in front of the read, and you might want to use read -r as well:
while IFS=$'\n' read -r filename; do ...; done < "$fileList"

Resources