Linux Command Ambiguous Redirect

Getting an ambiguous redirect error

Bash can be pretty obtuse sometimes.

The following commands all return different error messages for basically the same error:

$ echo hello >
bash: syntax error near unexpected token `newline`

$ echo hello > ${NONEXISTENT}
bash: ${NONEXISTENT}: ambiguous redirect

$ echo hello > "${NONEXISTENT}"
bash: : No such file or directory

Adding quotes around the variable seems to be a good way to deal with the "ambiguous redirect" message: You tend to get a better message when you've made a typing mistake -- and when the error is due to spaces in the filename, using quotes is the fix.

How to solve this ambiguous redirect error

the most logical way of doing it is to redirect from inside the loop instead, but not directly (thanks 123 for the comment: file cannot be input and output as the same time, maybe here it could work since windows loop seems to work, but let's not take useless risks...)

for f in ./*.fa ; do ./anchor $f -d ./ > /tmp/something; cat /tmp/something >> $f; done 

BTW: I wouldn't dare trying to explain what your original code does, is f defined/when $f is evaluated (before or after entering the for loop).

My guess is that $f just not evaluated and considered as $f literally, which confuses bash.

At any rate, it's incorrect.

EDIT: the windows version

for %F in ("*.fa") do anchor %F -d ./ >> %%F

does the redirection inside the loop (unlike your unix attempt), and it's really surprising that it works because of windows file locking...

What could happen (not sure) is that windows doesn't try to append to the file before something is issued on standard output, and at that moment, the program has closed the file as input.

Ambiguous redirect error in shell scripting when creating file name with date

The $(date) in your example produces a timestamp with blanks. You might either use your function ($(timestamp)) instead, or quote the whole target filename (or both):

echo bla >> "/home/pi/logs/temperature_log_$(timestamp).txt"

And it is best to actually evaluate the timestamp in the filename only before the loop, otherwise you get a new file every second or minute:

# %F: full date; same as %Y-%m-%d
logfile = "/home/pi/logs/temperature_log_$(date +%F).txt"
echo "Temperature Log_$(date)" > "$logfile" # overwrite if started 2 times a day
for i in {1..5}
do
temp=$(/opt/vc/bin/vcgencmd measure_temp)
temp=${temp:5:9}
echo "${temp} $(timestamp)" >> "$logfile"
sleep 1
done

Ambiguous redirect error when executing a script

The first line of your error message is telling you that you have a carriage return at the end of your line.

You have several ways to solve the problem:

  1. Make sure your script has unix-style line endings (eg. dos2unix)

  2. Add a statement terminator to the end of each command, such as: ; #

Linux command ambiguous redirect

The I/O redirection operators <, >, etc. all only take one word as their argument, and use that as a filename. Anything else is considered part of the command line.

So when you run this:

cat ../header.txt > find -name *.c

It's exactly the same as this:

cat ../header.txt -name *.c > find

That's probably not going to do anything useful.

Another problem: your *.c isn't escaped or quoted, so bash will expand it rather than passing it to find.


You can do what you seem to want with tee, which accepts any number of arguments:

cat ../header.txt | tee *.c

And then you don't even need cat any more, really.

tee *.c < ../header.txt

Of course, you could just as well do this with cp. Perhaps you meant to append to these files? If so, pass -a to tee as well.


Interesting trivia: zsh and some other shells will let you have multiple > operators, which works just like tee. (Multiple < is also allowed and works like cat.)

cat infile > outfile1 > outfile2

But you have to actually list every file individually, so you can't use this shortcut with a glob like *.c.

Ambiguous redirect error with echo

You don't need to touch if you are going to overwrite the files immediately anyway.

echo "." | tee a{1..9}.txt >/dev/null

If you want to overwrite all existing files matching a specific wildcard expression, you can use that as the argument to tee, of course:

echo "." | tee *.txt >/dev/null

You generally cannot redirect to a wildcard expression unless you are sure that it expands to exactly one existing file.

Ambiguous redirect or : : No such file or directory trying to save while loop's output to file

Try this:

#!/bin/bash

mkdir -p ./err_logs
mkdir -p ./out_logs
err_path=$(realpath ./err_logs)
out_path=$(realpath ./out_logs)
err_log_path="${err_path}/err_$(date +"%d_%m").log"
out_log_path="${out_path}/out_$(date +"%d_%m").log"

while true;
do
echo "starting main from bash"
>&2 echo "starting main from bash"
python3 main.py
echo "done running main sleeping"
sleep 10
echo "list of remaining python processes: "
ps -ax | grep python
echo "closing all of the remaining processes."
ps ax | grep "python" | grep -v grep | awk '{print $1}' | xargs kill;
echo "done closing subprocesses"
# echo "-------test---------" > $out_log_path 2> $err_log_path
done > $out_log_path 2> $err_log_path

Or, if the code has to run over several different days, this:

#!/bin/bash

while true;
do
mkdir -p ./err_logs
mkdir -p ./out_logs
err_path=$(realpath ./err_logs)
out_path=$(realpath ./out_logs)
err_log_path="${err_path}/err_$(date +"%d_%m").log"
out_log_path="${out_path}/out_$(date +"%d_%m").log"
echo "starting main from bash" >> $out_log_path 2>> $err_log_path
>&2 echo "starting main from bash"
python3 main.py >> $out_log_path 2>> $err_log_path
echo "done running main sleeping" >> $out_log_path 2>> $err_log_path
sleep 10
echo "list of remaining python processes: " >> $out_log_path 2>> $err_log_path
ps -ax | grep python >> $out_log_path 2>> $err_log_path
echo "closing all of the remaining processes." >> $out_log_path 2>> $err_log_path
ps ax | grep "python" | grep -v grep | awk '{print $1}' | xargs kill >> $out_log_path 2>> $err_log_path
echo "done closing subprocesses" >> $out_log_path 2>> $err_log_path
echo "-------test---------" > $out_log_path 2>> $err_log_path
done

But this second option is not recommended.



Related Topics



Leave a reply



Submit