why 'read' command in shell script is missing initial characters?
This is pretty well explained in this post I'm reading a file line by line and running ssh or ffmpeg, only the first line gets processed!. When reading a file line by line, if a command inside the loop also reads stdin, it can exhaust the input file. In your case ffmpeg
also reads from stdin.
The most common symptom of this is a while read loop only running once, even though the input contains many lines. This is because the rest of the lines are swallowed by the offending command. The most common fix for the problem is to close the stdin of the ffmpeg
by doing < /dev/null
ffmpeg -y -i "$ifile" -c:v libx264rgb -b:v 512k -bf 0 -pix_fmt rgb24 -r 25 -strict -2 "$ofile" < /dev/null
or use another file descriptor other than standard input
while read -r line <&3; do
ifile="$line"
ofile="abc_${line}"
ffmpeg -y -i "$ifile" -c:v libx264rgb -b:v 512k -bf 0 -pix_fmt rgb24 -r 25 -strict -2 "$ofile"
done 3<file
Or your problem could altogether be a case of the input file having DOS style line endings carried over from a DOS environment. You can check that out by running the file
command on the input file (file file_list
) which could show CRLF line terminators
. In such case do a clean-up of the input file as dos2unix file_list
and re-run your script.
Bash script removing first letter
The reason you're missing the first character of the usernames is precisely the same as the reason your pause doesn't work: your pause (read -n 1 -p
) reads one character from stdin
. However, stdin
has been redirected to the datafile, so it reads the first character of the username.
You really need to quote variables in expansions. Get in the habit of doing so. It's much safer.
I don't know what the replacement line does either: as you present it, it looks like a no-op but I suppose it's possible that one of the spaces is a tab. Anyway, it is unnecessary. You can replace all of that fooling around with shell variables like this:
while read -r VARUSER VARPASS ignore_rest_of_line; do
echo "Username: $VARUSER Password: $VARPASS"
imapsync --host1 123.456.789.123 --user1 "$VARUSER" \
--password1 "$VARPASS" --authmech1 PLAIN \
--host2 999.888.777.123 \
--user2 "$VARUSER*masteruser@mydomain.com" \
--password2 notreallypasswordXD \
--authmech2 PLAIN --exclude 'Trash|Spam'
echo "Done!"
echo
read -n 1 -s < /dev/tty
done < mailusers.cfg
first character of string in shell not working
It works if while
is replaced with an if-then
statement:
while IFS=$'\t' read -r -a myArray
do
like=${myArray[0]}
position=${myArray[1]}
if [ "${like:0:1}" == "E" ]
then
file=$like."Rput"
echo "$file"
fi
done
Note also that spaces are important. The following tests first character of like
for equality with E
:
[ "${like:0:1}" == "E" ]
But, the following does something unrelated:
[ "${like:0:1}"=="E" ]
Since the equal sign here is not separated by spaces, "${like:0:1}"=="E"
is interpreted simply as a single string. Tests of a single string return true if the string is nonempty and false if it is empty. Since ${like:0:1}"=="E"
is always non-empty, it will always return true.
Bash: Special characters lost when reading file
You lost the backslashes and spaces because bash (via its read builtin) is evaluating the value of the text - substituting variables, looking for escape characters (tab, newline), etc. See the manpage for some details. Also, echo will combine whitespace.
As far as preserving them, I'm not sure you can. You'd probably get the backslashes back by doing:
while read -r line
do
echo $line
done < "my.tex"
which should modify read to not try to evaluate the backslashes. It will probably still swallow the leading spaces, though.
Edit: setting the $IFS
special variable to the empty string, like this:
export IFS=
will cause the spaces to be preserved in this case.
character missing when reading from file in shell script
while IFS= read -r line; do
echo "$line"
done < namespaces.txt
This is the correct way to read and print a line at a time. "$line"
is quoted, and IFS
can be set to empty.
Check for IFS=\n
, or similar, in your script. Somewhere, you have set IFS
to contain n
. Then when you print $line
with no quotes, it gets split in to multiple words by IFS
(n
), and echo prints each word given to it, with a space in between.
While loop stops reading after the first line in Bash
The problem is that do_work.sh
runs ssh
commands and by default ssh
reads from stdin which is your input file. As a result, you only see the first line processed, because the command consumes the rest of the file and your while loop terminates.
This happens not just for ssh
, but for any command that reads stdin, including mplayer
, ffmpeg
, HandBrakeCLI
, httpie
, brew install
, and more.
To prevent this, pass the -n
option to your ssh
command to make it read from /dev/null
instead of stdin. Other commands have similar flags, or you can universally use < /dev/null
.
Bash read ignores leading spaces
This is covered in the Bash FAQ entry on reading data line-by-line.
The read command modifies each line read; by default it removes all leading and trailing whitespace characters (spaces and tabs, or any whitespace characters present in IFS). If that is not desired, the IFS variable has to be cleared:
# Exact lines, no trimming
while IFS= read -r line; do
printf '%s\n' "$line"
done < "$file"
As Charles Duffy correctly points out (and I'd missed by focusing on the IFS
issue); if you want to see the spaces in your output you also need to quote the variable when you use it or the shell will, once again, drop the whitespace.
Notes about some of the other differences in that quoted snippet as compared to your original code.
The use of the -r
argument to read
is covered in a single sentence at the top of the previously linked page.
The -r option to read prevents backslash interpretation (usually used as a backslash newline pair, to continue over multiple lines). Without this option, any backslashes in the input will be discarded. You should almost always use the -r option with read.
As to using printf
instead of echo
there the behavior of echo
is, somewhat unfortunately, not portably consistent across all environments and the differences can be awkward to deal with. printf
on the other hand is consistent and can be used entirely robustly.
Bash script prints Command Not Found on empty lines
Make sure your first line is:
#!/bin/bash
Enter your path to bash if it is not /bin/bash
Try running:
dos2unix script.sh
That wil convert line endings, etc from Windows to unix format. i.e. it strips \r (CR) from line endings to change them from \r\n (CR+LF)
to \n (LF)
.
More details about the dos2unix
command (man page)
Another way to tell if your file is in dos/Win format:
cat scriptname.sh | sed 's/\r/<CR>/'
The output will look something like this:
#!/bin/sh<CR>
<CR>
echo Hello World<CR>
<CR>
This will output the entire file text with <CR>
displayed for each \r
character in the file.
Related Topics
Does Chrome 12 Really Support CSS 3D Transforms? Including on Linux
Return Values from Bash Script
Fedora 28/Glibc 2.27 Libm.So.6 Logf() and Powf() C++
Expect Utility Is Not Working When Executing from Jenkins
How to Set The Current Directory of a Debugged Process
How to Rename a Shared Library to Avoid Same-Name Conflict
Need Some Advise to Begin Programming on Arm (With Linux) Platform
Controlling The Boot Screen on Linux Embedded App
File/Directory Permissions Trailing + ( Drwxr-Xr-X+ )
.Lis Files Generated While Compiling Pro*C Code in Linux
Partitioning Images Based on Their White Space
Docker Rootless Unable to Pull Images
Bash Command Line Arguments Passed to Sed via Ssh
How to Extract Email Headers Extending on Multiple Lines from File